Skip to content

Commit 46ce9dd

Browse files
rp-dhslove
authored andcommitted
Linstor fix host picking (apache#12047)
1 parent 2c680cf commit 46ce9dd

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
@@ -64,6 +64,8 @@
6464
import com.cloud.api.storage.LinstorRevertBackupSnapshotCommand;
6565
import com.cloud.configuration.Config;
6666
import com.cloud.host.Host;
67+
import com.cloud.host.HostVO;
68+
import com.cloud.host.Status;
6769
import com.cloud.host.dao.HostDao;
6870
import com.cloud.resource.ResourceState;
6971
import com.cloud.storage.DataStoreRole;
@@ -923,9 +925,10 @@ private String revertSnapshotFromImageStore(
923925
_backupsnapshotwait,
924926
VirtualMachineManager.ExecuteInSequence.value());
925927

926-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, rscName);
928+
final StoragePool pool = (StoragePool) volumeInfo.getDataStore();
929+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, pool, rscName);
927930
if (optEP.isEmpty()) {
928-
optEP = getLinstorEP(linstorApi, rscName);
931+
optEP = getLinstorEP(linstorApi, pool, rscName);
929932
}
930933

931934
if (optEP.isPresent()) {
@@ -1065,13 +1068,29 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10651068
Answer answer = copyVolume(srcData, dstData);
10661069
res = new CopyCommandResult(null, answer);
10671070
} else {
1068-
Answer answer = new Answer(null, false, "noimpl");
1069-
res = new CopyCommandResult(null, answer);
1070-
res.setResult("Not implemented yet");
1071+
throw new CloudRuntimeException("Not implemented for Linstor primary storage.");
10711072
}
10721073
callback.complete(res);
10731074
}
10741075

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

1105-
if (host == null)
1106-
{
1107-
logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1108-
return Optional.empty();
1109-
}
1110-
else
1111-
{
1112-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1113-
}
1119+
logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1120+
return Optional.empty();
11141121
}
11151122

1116-
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, String rscName) throws ApiException {
1123+
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, StoragePool storagePool, String rscName)
1124+
throws ApiException {
11171125
List<com.linbit.linstor.api.model.StoragePool> linSPs = LinstorUtil.getDiskfulStoragePools(api, rscName);
11181126
if (linSPs != null) {
1119-
for (com.linbit.linstor.api.model.StoragePool sp : linSPs) {
1120-
Host host = _hostDao.findByName(sp.getNodeName());
1121-
if (host != null && host.getResourceState() == ResourceState.Enabled) {
1122-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1123-
}
1127+
List<String> linstorNodeNames = linSPs.stream()
1128+
.map(com.linbit.linstor.api.model.StoragePool::getNodeName)
1129+
.collect(Collectors.toList());
1130+
Host host = getEnabledClusterHost(storagePool, linstorNodeNames);
1131+
if (host != null) {
1132+
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
11241133
}
11251134
}
11261135
logger.error("Linstor: No diskfull host found.");
@@ -1201,12 +1210,12 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
12011210
VirtualMachineManager.ExecuteInSequence.value());
12021211

12031212
try {
1204-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1213+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12051214
if (optEP.isPresent()) {
12061215
answer = optEP.get().sendMessage(cmd);
12071216
} else {
1208-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
12091217
deleteResourceDefinition(pool, rscName);
1218+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12101219
}
12111220
} catch (ApiException exc) {
12121221
logger.error("copy template failed: ", exc);
@@ -1243,12 +1252,12 @@ private Answer copyVolume(DataObject srcData, DataObject dstData) {
12431252
Answer answer;
12441253

12451254
try {
1246-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1255+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12471256
if (optEP.isPresent()) {
12481257
answer = optEP.get().sendMessage(cmd);
12491258
}
12501259
else {
1251-
answer = new Answer(cmd, false, "Unable to get matching Linstor endpoint.");
1260+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12521261
}
12531262
} catch (ApiException exc) {
12541263
logger.error("copy volume failed: ", exc);
@@ -1281,14 +1290,14 @@ private Answer copyFromTemporaryResource(
12811290
try {
12821291
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
12831292

1284-
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
1293+
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, pool, restoreName);
12851294
if (optEPAny.isPresent()) {
12861295
// patch the src device path to the temporary linstor resource
12871296
snapshotObject.setPath(devName);
12881297
origCmd.setSrcTO(snapshotObject.getTO());
12891298
answer = optEPAny.get().sendMessage(origCmd);
1290-
} else{
1291-
answer = new Answer(origCmd, false, "Unable to get matching Linstor endpoint.");
1299+
} else {
1300+
throw new CloudRuntimeException("Unable to get matching Linstor endpoint.");
12921301
}
12931302
} finally {
12941303
// delete the temporary resource, noop if already gone
@@ -1350,7 +1359,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
13501359
VirtualMachineManager.ExecuteInSequence.value());
13511360
cmd.setOptions(options);
13521361

1353-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
1362+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, pool, rscName);
13541363
Answer answer;
13551364
if (optEP.isPresent()) {
13561365
answer = optEP.get().sendMessage(cmd);

0 commit comments

Comments
 (0)