Skip to content

Commit

Permalink
linstor: cleanup diskless nodes on disconnect (#8790)
Browse files Browse the repository at this point in the history
  • Loading branch information
rp- authored Apr 26, 2024
1 parent eead271 commit 9d5d4e5
Showing 1 changed file with 74 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.cloud.storage.Storage;
import com.cloud.utils.exception.CloudRuntimeException;
import com.linbit.linstor.api.ApiClient;
import com.linbit.linstor.api.ApiConsts;
import com.linbit.linstor.api.ApiException;
import com.linbit.linstor.api.Configuration;
import com.linbit.linstor.api.DevelopersApi;
Expand Down Expand Up @@ -103,6 +104,10 @@ private void logLinstorAnswer(@Nonnull ApiCallRc answer) {
}
}

private void logLinstorAnswers(@Nonnull ApiCallRcList answers) {
answers.forEach(this::logLinstorAnswer);
}

private void checkLinstorAnswersThrow(@Nonnull ApiCallRcList answers) {
answers.forEach(this::logLinstorAnswer);
if (answers.hasError())
Expand Down Expand Up @@ -316,23 +321,90 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
return true;
}

private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
{
if (volumePath == null) {
return false;
}

s_logger.debug("Linstor: Using storage pool: " + pool.getUuid());
final DevelopersApi api = getLinstorAPI(pool);

Optional<ResourceWithVolumes> optRsc;
try
{
List<ResourceWithVolumes> resources = api.viewResources(
Collections.singletonList(localNodeName),
null,
null,
null,
null,
null);

optRsc = getResourceByPath(resources, volumePath);
} catch (ApiException apiEx) {
// couldn't query linstor controller
s_logger.error(apiEx.getBestMessage());
return false;
}


if (optRsc.isPresent()) {
try {
Resource rsc = optRsc.get();

// if diskless resource remove it, in the worst case it will be transformed to a tiebreaker
if (rsc.getFlags() != null &&
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) &&
!rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) {
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName);
logLinstorAnswers(delAnswers);
}

// remove allow-two-primaries
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
ApiCallRcList answers = api.resourceDefinitionModify(rsc.getName(), rdm);
if (answers.hasError()) {
s_logger.error(
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
rsc.getName(), LinstorUtil.getBestErrorMessage(answers)));
// do not fail here as removing allow-two-primaries property isn't fatal
}
} catch (ApiException apiEx) {
s_logger.error(apiEx.getBestMessage());
// do not fail here as removing allow-two-primaries property or deleting diskless isn't fatal
}

return true;
}

s_logger.warn("Linstor: Couldn't find resource for this path: " + volumePath);
return false;
}

@Override
public boolean disconnectPhysicalDisk(String volumePath, KVMStoragePool pool)
{
s_logger.debug("Linstor: disconnectPhysicalDisk " + pool.getUuid() + ":" + volumePath);
if (MapStorageUuidToStoragePool.containsValue(pool)) {
return tryDisconnectLinstor(volumePath, pool);
}
return false;
}

@Override
public boolean disconnectPhysicalDisk(Map<String, String> volumeToDisconnect)
{
// as of now this is only relevant for iscsi targets
s_logger.info("Linstor: disconnectPhysicalDisk(Map<String, String> volumeToDisconnect) called?");
return false;
}

private Optional<ResourceWithVolumes> getResourceByPath(final List<ResourceWithVolumes> resources, String path) {
return resources.stream()
.filter(rsc -> rsc.getVolumes().stream()
.anyMatch(v -> v.getDevicePath().equals(path)))
.anyMatch(v -> path.equals(v.getDevicePath())))
.findFirst();
}

Expand All @@ -353,46 +425,8 @@ public boolean disconnectPhysicalDiskByPath(String localPath)
s_logger.debug("Linstor: disconnectPhysicalDiskByPath " + localPath);
final KVMStoragePool pool = optFirstPool.get();

s_logger.debug("Linstor: Using storpool: " + pool.getUuid());
final DevelopersApi api = getLinstorAPI(pool);

Optional<ResourceWithVolumes> optRsc;
try {
List<ResourceWithVolumes> resources = api.viewResources(
Collections.singletonList(localNodeName),
null,
null,
null,
null,
null);

optRsc = getResourceByPath(resources, localPath);
} catch (ApiException apiEx) {
// couldn't query linstor controller
s_logger.error(apiEx.getBestMessage());
return false;
}

if (optRsc.isPresent()) {
try {
Resource rsc = optRsc.get();
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
ApiCallRcList answers = api.resourceDefinitionModify(rsc.getName(), rdm);
if (answers.hasError()) {
s_logger.error(
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
rsc.getName(), LinstorUtil.getBestErrorMessage(answers)));
// do not fail here as removing allow-two-primaries property isn't fatal
}
} catch(ApiException apiEx){
s_logger.error(apiEx.getBestMessage());
// do not fail here as removing allow-two-primaries property isn't fatal
}
return true;
}
return tryDisconnectLinstor(localPath, pool);
}
s_logger.info("Linstor: Couldn't find resource for this path: " + localPath);
return false;
}

Expand Down

0 comments on commit 9d5d4e5

Please sign in to comment.