Skip to content

Commit 1e9040f

Browse files
committed
linstor: Pick correct host for agent operations
Before it was possible that a Host was picked for the primary storage that was not even part of cluster, now we only consider hosts from either the same cluster or same zone depending on primary storage settings.
1 parent 425d257 commit 1e9040f

File tree

1 file changed

+47
-39
lines changed

1 file changed

+47
-39
lines changed

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

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
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;
6667
import com.cloud.host.dao.HostDao;
6768
import com.cloud.resource.ResourceState;
6869
import com.cloud.storage.DataStoreRole;
@@ -921,9 +922,10 @@ private String revertSnapshotFromImageStore(
921922
_backupsnapshotwait,
922923
VirtualMachineManager.ExecuteInSequence.value());
923924

924-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, rscName);
925+
final StoragePool pool = (StoragePool) volumeInfo.getDataStore();
926+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(linstorApi, pool, rscName);
925927
if (optEP.isEmpty()) {
926-
optEP = getLinstorEP(linstorApi, rscName);
928+
optEP = getLinstorEP(linstorApi, pool, rscName);
927929
}
928930

929931
if (optEP.isPresent()) {
@@ -1068,6 +1070,22 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10681070
callback.complete(res);
10691071
}
10701072

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

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

1112-
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, String rscName) throws ApiException {
1118+
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, StoragePool storagePool, String rscName)
1119+
throws ApiException {
11131120
List<com.linbit.linstor.api.model.StoragePool> linSPs = LinstorUtil.getDiskfulStoragePools(api, rscName);
11141121
if (linSPs != null) {
1115-
for (com.linbit.linstor.api.model.StoragePool sp : linSPs) {
1116-
Host host = _hostDao.findByName(sp.getNodeName());
1117-
if (host != null && host.getResourceState() == ResourceState.Enabled) {
1118-
return Optional.of(RemoteHostEndPoint.getHypervisorHostEndPoint(host));
1119-
}
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));
11201128
}
11211129
}
11221130
logger.error("Linstor: No diskfull host found.");
@@ -1197,7 +1205,7 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
11971205
VirtualMachineManager.ExecuteInSequence.value());
11981206

11991207
try {
1200-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1208+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12011209
if (optEP.isPresent()) {
12021210
answer = optEP.get().sendMessage(cmd);
12031211
} else {
@@ -1239,7 +1247,7 @@ private Answer copyVolume(DataObject srcData, DataObject dstData) {
12391247
Answer answer;
12401248

12411249
try {
1242-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1250+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12431251
if (optEP.isPresent()) {
12441252
answer = optEP.get().sendMessage(cmd);
12451253
}
@@ -1277,7 +1285,7 @@ private Answer copyFromTemporaryResource(
12771285
try {
12781286
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
12791287

1280-
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
1288+
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, pool, restoreName);
12811289
if (optEPAny.isPresent()) {
12821290
// patch the src device path to the temporary linstor resource
12831291
snapshotObject.setPath(devName);
@@ -1346,7 +1354,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
13461354
VirtualMachineManager.ExecuteInSequence.value());
13471355
cmd.setOptions(options);
13481356

1349-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
1357+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, pool, rscName);
13501358
Answer answer;
13511359
if (optEP.isPresent()) {
13521360
answer = optEP.get().sendMessage(cmd);

0 commit comments

Comments
 (0)