Skip to content

Commit b7d9ded

Browse files
rp-dhslove
authored andcommitted
linstor: Do not pretend handling disconnect paths that are non Linstor (apache#8897)
1 parent 011cfb5 commit b7d9ded

1 file changed

Lines changed: 102 additions & 49 deletions

File tree

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

Lines changed: 102 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@
3535
import org.libvirt.LibvirtException;
3636

3737
import com.linbit.linstor.api.ApiClient;
38+
import com.linbit.linstor.api.ApiConsts;
3839
import com.linbit.linstor.api.ApiException;
3940
import com.linbit.linstor.api.Configuration;
4041
import com.linbit.linstor.api.DevelopersApi;
4142
import com.linbit.linstor.api.model.ApiCallRc;
4243
import com.linbit.linstor.api.model.ApiCallRcList;
4344
import com.linbit.linstor.api.model.Properties;
4445
import com.linbit.linstor.api.model.ProviderKind;
46+
import com.linbit.linstor.api.model.Resource;
4547
import com.linbit.linstor.api.model.ResourceDefinition;
4648
import com.linbit.linstor.api.model.ResourceDefinitionModify;
4749
import com.linbit.linstor.api.model.ResourceGroupSpawn;
@@ -80,6 +82,10 @@ private void logLinstorAnswer(@Nonnull ApiCallRc answer) {
8082
}
8183
}
8284

85+
private void logLinstorAnswers(@Nonnull ApiCallRcList answers) {
86+
answers.forEach(this::logLinstorAnswer);
87+
}
88+
8389
private void checkLinstorAnswersThrow(@Nonnull ApiCallRcList answers) {
8490
answers.forEach(this::logLinstorAnswer);
8591
if (answers.hasError())
@@ -239,6 +245,28 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
239245
}
240246
}
241247

248+
/**
249+
* Checks if the given resource is in use by drbd on any host and
250+
* if so set the drbd option allow-two-primaries
251+
* @param api linstor api object
252+
* @param rscName resource name to set allow-two-primaries if in use
253+
* @throws ApiException if any problem connecting to the Linstor controller
254+
*/
255+
private void allow2PrimariesIfInUse(DevelopersApi api, String rscName) throws ApiException {
256+
if (LinstorUtil.isResourceInUse(api, rscName)) {
257+
// allow 2 primaries for live migration, should be removed by disconnect on the other end
258+
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
259+
Properties props = new Properties();
260+
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
261+
rdm.setOverrideProps(props);
262+
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
263+
if (answers.hasError()) {
264+
logger.error("Unable to set 'allow-two-primaries' on {} ", rscName);
265+
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
266+
}
267+
}
268+
}
269+
242270
@Override
243271
public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<String, String> details)
244272
{
@@ -265,40 +293,98 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
265293

266294
try
267295
{
268-
// allow 2 primaries for live migration, should be removed by disconnect on the other end
269-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
270-
Properties props = new Properties();
271-
props.put("DrbdOptions/Net/allow-two-primaries", "yes");
272-
rdm.setOverrideProps(props);
273-
ApiCallRcList answers = api.resourceDefinitionModify(rscName, rdm);
274-
if (answers.hasError()) {
275-
logger.error("Unable to set 'allow-two-primaries' on " + rscName);
276-
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
277-
}
296+
allow2PrimariesIfInUse(api, rscName);
278297
} catch (ApiException apiEx) {
279298
logger.error(apiEx);
280299
// do not fail here as adding allow-two-primaries property is only a problem while live migrating
281300
}
282301
return true;
283302
}
284303

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

292376
@Override
293377
public boolean disconnectPhysicalDisk(Map<String, String> volumeToDisconnect)
294378
{
379+
// as of now this is only relevant for iscsi targets
380+
logger.info("Linstor: disconnectPhysicalDisk(Map<String, String> volumeToDisconnect) called?");
295381
return false;
296382
}
297383

298384
private Optional<ResourceWithVolumes> getResourceByPath(final List<ResourceWithVolumes> resources, String path) {
299385
return resources.stream()
300386
.filter(rsc -> rsc.getVolumes().stream()
301-
.anyMatch(v -> v.getDevicePath().equals(path)))
387+
.anyMatch(v -> path.equals(v.getDevicePath())))
302388
.findFirst();
303389
}
304390

@@ -319,42 +405,9 @@ public boolean disconnectPhysicalDiskByPath(String localPath)
319405
logger.debug("Linstor: disconnectPhysicalDiskByPath " + localPath);
320406
final KVMStoragePool pool = optFirstPool.get();
321407

322-
logger.debug("Linstor: Using storpool: " + pool.getUuid());
323-
final DevelopersApi api = getLinstorAPI(pool);
324-
325-
try
326-
{
327-
List<ResourceWithVolumes> resources = api.viewResources(
328-
Collections.singletonList(localNodeName),
329-
null,
330-
null,
331-
null,
332-
null,
333-
null);
334-
335-
Optional<ResourceWithVolumes> rsc = getResourceByPath(resources, localPath);
336-
337-
if (rsc.isPresent())
338-
{
339-
ResourceDefinitionModify rdm = new ResourceDefinitionModify();
340-
rdm.deleteProps(Collections.singletonList("DrbdOptions/Net/allow-two-primaries"));
341-
ApiCallRcList answers = api.resourceDefinitionModify(rsc.get().getName(), rdm);
342-
if (answers.hasError()) {
343-
logger.error(
344-
String.format("Failed to remove 'allow-two-primaries' on %s: %s",
345-
rsc.get().getName(), LinstorUtil.getBestErrorMessage(answers)));
346-
// do not fail here as removing allow-two-primaries property isn't fatal
347-
}
348-
349-
return true;
350-
}
351-
logger.warn("Linstor: Couldn't find resource for this path: " + localPath);
352-
} catch (ApiException apiEx) {
353-
logger.error(apiEx.getBestMessage());
354-
// do not fail here as removing allow-two-primaries property isn't fatal
355-
}
408+
return tryDisconnectLinstor(localPath, pool);
356409
}
357-
return true;
410+
return false;
358411
}
359412

360413
@Override
@@ -520,4 +573,4 @@ public long getUsed(LinstorStoragePool pool) {
520573
throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx);
521574
}
522575
}
523-
}
576+
}

0 commit comments

Comments
 (0)