Skip to content

Commit af48a83

Browse files
committed
linstor: cleanup diskless nodes on disconnect
If disconnect is running on a diskless node, try to cleanup the resource. Also fix a bug with the return value of disconnectPhysicalDiskByPath that was introduced with 56f0448
1 parent f8fd22c commit af48a83

1 file changed

Lines changed: 79 additions & 44 deletions

File tree

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java

Lines changed: 79 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@
3838
import com.cloud.storage.Storage;
3939
import com.cloud.utils.exception.CloudRuntimeException;
4040
import com.linbit.linstor.api.ApiClient;
41+
import com.linbit.linstor.api.ApiConsts;
4142
import com.linbit.linstor.api.ApiException;
4243
import com.linbit.linstor.api.Configuration;
4344
import com.linbit.linstor.api.DevelopersApi;
4445
import com.linbit.linstor.api.model.ApiCallRc;
4546
import com.linbit.linstor.api.model.ApiCallRcList;
4647
import com.linbit.linstor.api.model.Properties;
4748
import com.linbit.linstor.api.model.ProviderKind;
49+
import com.linbit.linstor.api.model.Resource;
4850
import com.linbit.linstor.api.model.ResourceDefinition;
4951
import com.linbit.linstor.api.model.ResourceDefinitionModify;
5052
import com.linbit.linstor.api.model.ResourceGroup;
@@ -102,6 +104,10 @@ private void logLinstorAnswer(@Nonnull ApiCallRc answer) {
102104
}
103105
}
104106

107+
private void logLinstorAnswers(@Nonnull ApiCallRcList answers) {
108+
answers.forEach(this::logLinstorAnswer);
109+
}
110+
105111
private void checkLinstorAnswersThrow(@Nonnull ApiCallRcList answers) {
106112
answers.forEach(this::logLinstorAnswer);
107113
if (answers.hasError())
@@ -302,26 +308,89 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
302308
return true;
303309
}
304310

311+
private Optional<ResourceWithVolumes> getResourceByPath(final List<ResourceWithVolumes> resources, String path) {
312+
return resources.stream()
313+
.filter(rsc -> rsc.getVolumes().stream()
314+
.anyMatch(v -> v.getDevicePath().equals(path)))
315+
.findFirst();
316+
}
317+
318+
private boolean tryDisconnectLinstor(String volumePath, KVMStoragePool pool)
319+
{
320+
s_logger.debug("Linstor: Using storage pool: " + pool.getUuid());
321+
final DevelopersApi api = getLinstorAPI(pool);
322+
323+
Optional<ResourceWithVolumes> optRsc;
324+
try
325+
{
326+
List<ResourceWithVolumes> resources = api.viewResources(
327+
Collections.singletonList(localNodeName),
328+
null,
329+
null,
330+
null,
331+
null,
332+
null);
333+
334+
optRsc = getResourceByPath(resources, volumePath);
335+
} catch (ApiException apiEx) {
336+
// couldn't query linstor controller
337+
s_logger.error(apiEx.getBestMessage());
338+
return false;
339+
}
340+
341+
342+
if (optRsc.isPresent()) {
343+
try {
344+
Resource rsc = optRsc.get();
345+
346+
// if diskless resource remove it, in the worst case it will be transformed to a tiebreaker
347+
if (rsc.getFlags() != null &&
348+
rsc.getFlags().contains(ApiConsts.FLAG_DRBD_DISKLESS) &&
349+
!rsc.getFlags().contains(ApiConsts.FLAG_TIE_BREAKER)) {
350+
ApiCallRcList delAnswers = api.resourceDelete(rsc.getName(), localNodeName);
351+
logLinstorAnswers(delAnswers);
352+
}
353+
354+
// remove allow-two-primaries
355+
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
356+
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
357+
ApiCallRcList answers = api.resourceDefinitionModify(rsc.getName(), rdm);
358+
if (answers.hasError()) {
359+
s_logger.error(
360+
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
361+
rsc.getName(), LinstorUtil.getBestErrorMessage(answers)));
362+
// do not fail here as removing allow-two-primaries property isn't fatal
363+
}
364+
} catch (ApiException apiEx) {
365+
s_logger.error(apiEx.getBestMessage());
366+
// do not fail here as removing allow-two-primaries property or deleting diskless isn't fatal
367+
}
368+
369+
return true;
370+
}
371+
372+
s_logger.warn("Linstor: Couldn't find resource for this path: " + volumePath);
373+
return false;
374+
}
375+
305376
@Override
306377
public boolean disconnectPhysicalDisk(String volumePath, KVMStoragePool pool)
307378
{
308379
s_logger.debug("Linstor: disconnectPhysicalDisk " + pool.getUuid() + ":" + volumePath);
309-
return true;
380+
if (MapStorageUuidToStoragePool.containsValue(pool)) {
381+
return tryDisconnectLinstor(volumePath, pool);
382+
}
383+
return false;
310384
}
311385

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

318-
private Optional<ResourceWithVolumes> getResourceByPath(final List<ResourceWithVolumes> resources, String path) {
319-
return resources.stream()
320-
.filter(rsc -> rsc.getVolumes().stream()
321-
.anyMatch(v -> v.getDevicePath().equals(path)))
322-
.findFirst();
323-
}
324-
325394
/**
326395
* disconnectPhysicalDiskByPath is called after e.g. a live migration.
327396
* The problem is we have no idea just from the path to which linstor-controller
@@ -339,43 +408,9 @@ public boolean disconnectPhysicalDiskByPath(String localPath)
339408
s_logger.debug("Linstor: disconnectPhysicalDiskByPath " + localPath);
340409
final KVMStoragePool pool = optFirstPool.get();
341410

342-
s_logger.debug("Linstor: Using storpool: " + pool.getUuid());
343-
final DevelopersApi api = getLinstorAPI(pool);
344-
345-
try
346-
{
347-
List<ResourceWithVolumes> resources = api.viewResources(
348-
Collections.singletonList(localNodeName),
349-
null,
350-
null,
351-
null,
352-
null,
353-
null);
354-
355-
Optional<ResourceWithVolumes> rsc = getResourceByPath(resources, localPath);
356-
357-
if (rsc.isPresent())
358-
{
359-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
360-
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
361-
ApiCallRcList answers = api.resourceDefinitionModify(rsc.get().getName(), rdm);
362-
if (answers.hasError())
363-
{
364-
s_logger.error(
365-
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
366-
rsc.get().getName(), LinstorUtil.getBestErrorMessage(answers)));
367-
// do not fail here as removing allow-two-primaries property isn't fatal
368-
}
369-
370-
return true;
371-
}
372-
s_logger.warn("Linstor: Couldn't find resource for this path: " + localPath);
373-
} catch (ApiException apiEx) {
374-
s_logger.error(apiEx.getBestMessage());
375-
// do not fail here as removing allow-two-primaries property isn't fatal
376-
}
411+
return tryDisconnectLinstor(localPath, pool);
377412
}
378-
return true;
413+
return false;
379414
}
380415

381416
@Override

0 commit comments

Comments
 (0)