Skip to content

Commit 150be1c

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 150be1c

File tree

1 file changed

+50
-39
lines changed

1 file changed

+50
-39
lines changed

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

Lines changed: 50 additions & 39 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()) {
@@ -1068,6 +1071,24 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10681071
callback.complete(res);
10691072
}
10701073

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+
10711092
/**
10721093
* Tries to get a Linstor cloudstack end point, that is at least diskless.
10731094
*
@@ -1076,47 +1097,37 @@ public void copyAsync(DataObject srcData, DataObject dstData, AsyncCompletionCal
10761097
* @return Optional RemoteHostEndPoint if one could get found.
10771098
* @throws ApiException
10781099
*/
1079-
private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, String rscName) throws ApiException {
1100+
private Optional<RemoteHostEndPoint> getLinstorEP(DevelopersApi api, StoragePool storagePool, String rscName)
1101+
throws ApiException {
10801102
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-
}
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));
10981114
}
10991115
}
11001116

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-
}
1117+
logger.error("Linstor: Couldn't create a resource on any cloudstack host.");
1118+
return Optional.empty();
11101119
}
11111120

1112-
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, String rscName) throws ApiException {
1121+
private Optional<RemoteHostEndPoint> getDiskfullEP(DevelopersApi api, StoragePool storagePool, String rscName)
1122+
throws ApiException {
11131123
List<com.linbit.linstor.api.model.StoragePool> linSPs = LinstorUtil.getDiskfulStoragePools(api, rscName);
11141124
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-
}
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));
11201131
}
11211132
}
11221133
logger.error("Linstor: No diskfull host found.");
@@ -1197,7 +1208,7 @@ private Answer copyTemplate(DataObject srcData, DataObject dstData) {
11971208
VirtualMachineManager.ExecuteInSequence.value());
11981209

11991210
try {
1200-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1211+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12011212
if (optEP.isPresent()) {
12021213
answer = optEP.get().sendMessage(cmd);
12031214
} else {
@@ -1239,7 +1250,7 @@ private Answer copyVolume(DataObject srcData, DataObject dstData) {
12391250
Answer answer;
12401251

12411252
try {
1242-
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, rscName);
1253+
Optional<RemoteHostEndPoint> optEP = getLinstorEP(api, pool, rscName);
12431254
if (optEP.isPresent()) {
12441255
answer = optEP.get().sendMessage(cmd);
12451256
}
@@ -1277,7 +1288,7 @@ private Answer copyFromTemporaryResource(
12771288
try {
12781289
String devName = restoreResourceFromSnapshot(api, pool, rscName, snapshotName, restoreName);
12791290

1280-
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, restoreName);
1291+
Optional<RemoteHostEndPoint> optEPAny = getLinstorEP(api, pool, restoreName);
12811292
if (optEPAny.isPresent()) {
12821293
// patch the src device path to the temporary linstor resource
12831294
snapshotObject.setPath(devName);
@@ -1346,7 +1357,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
13461357
VirtualMachineManager.ExecuteInSequence.value());
13471358
cmd.setOptions(options);
13481359

1349-
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, rscName);
1360+
Optional<RemoteHostEndPoint> optEP = getDiskfullEP(api, pool, rscName);
13501361
Answer answer;
13511362
if (optEP.isPresent()) {
13521363
answer = optEP.get().sendMessage(cmd);

0 commit comments

Comments
 (0)