3838import com .cloud .storage .Storage ;
3939import com .cloud .utils .exception .CloudRuntimeException ;
4040import com .linbit .linstor .api .ApiClient ;
41+ import com .linbit .linstor .api .ApiConsts ;
4142import com .linbit .linstor .api .ApiException ;
4243import com .linbit .linstor .api .Configuration ;
4344import com .linbit .linstor .api .DevelopersApi ;
@@ -103,6 +104,10 @@ private void logLinstorAnswer(@Nonnull ApiCallRc answer) {
103104 }
104105 }
105106
107+ private void logLinstorAnswers (@ Nonnull ApiCallRcList answers ) {
108+ answers .forEach (this ::logLinstorAnswer );
109+ }
110+
106111 private void checkLinstorAnswersThrow (@ Nonnull ApiCallRcList answers ) {
107112 answers .forEach (this ::logLinstorAnswer );
108113 if (answers .hasError ())
@@ -303,23 +308,90 @@ public boolean connectPhysicalDisk(String volumePath, KVMStoragePool pool, Map<S
303308 return true ;
304309 }
305310
311+ private boolean tryDisconnectLinstor (String volumePath , KVMStoragePool pool )
312+ {
313+ if (volumePath == null ) {
314+ return false ;
315+ }
316+
317+ s_logger .debug ("Linstor: Using storage pool: " + pool .getUuid ());
318+ final DevelopersApi api = getLinstorAPI (pool );
319+
320+ Optional <ResourceWithVolumes > optRsc ;
321+ try
322+ {
323+ List <ResourceWithVolumes > resources = api .viewResources (
324+ Collections .singletonList (localNodeName ),
325+ null ,
326+ null ,
327+ null ,
328+ null ,
329+ null );
330+
331+ optRsc = getResourceByPath (resources , volumePath );
332+ } catch (ApiException apiEx ) {
333+ // couldn't query linstor controller
334+ s_logger .error (apiEx .getBestMessage ());
335+ return false ;
336+ }
337+
338+
339+ if (optRsc .isPresent ()) {
340+ try {
341+ Resource rsc = optRsc .get ();
342+
343+ // if diskless resource remove it, in the worst case it will be transformed to a tiebreaker
344+ if (rsc .getFlags () != null &&
345+ rsc .getFlags ().contains (ApiConsts .FLAG_DRBD_DISKLESS ) &&
346+ !rsc .getFlags ().contains (ApiConsts .FLAG_TIE_BREAKER )) {
347+ ApiCallRcList delAnswers = api .resourceDelete (rsc .getName (), localNodeName );
348+ logLinstorAnswers (delAnswers );
349+ }
350+
351+ // remove allow-two-primaries
352+ ResourceDefinitionModify rdm = new ResourceDefinitionModify ();
353+ rdm .deleteProps (Collections .singletonList ("DrbdOptions/Net/allow-two-primaries" ));
354+ ApiCallRcList answers = api .resourceDefinitionModify (rsc .getName (), rdm );
355+ if (answers .hasError ()) {
356+ s_logger .error (
357+ String .format ("Failed to remove 'allow-two-primaries' on %s: %s" ,
358+ rsc .getName (), LinstorUtil .getBestErrorMessage (answers )));
359+ // do not fail here as removing allow-two-primaries property isn't fatal
360+ }
361+ } catch (ApiException apiEx ) {
362+ s_logger .error (apiEx .getBestMessage ());
363+ // do not fail here as removing allow-two-primaries property or deleting diskless isn't fatal
364+ }
365+
366+ return true ;
367+ }
368+
369+ s_logger .warn ("Linstor: Couldn't find resource for this path: " + volumePath );
370+ return false ;
371+ }
372+
306373 @ Override
307374 public boolean disconnectPhysicalDisk (String volumePath , KVMStoragePool pool )
308375 {
309376 s_logger .debug ("Linstor: disconnectPhysicalDisk " + pool .getUuid () + ":" + volumePath );
377+ if (MapStorageUuidToStoragePool .containsValue (pool )) {
378+ return tryDisconnectLinstor (volumePath , pool );
379+ }
310380 return false ;
311381 }
312382
313383 @ Override
314384 public boolean disconnectPhysicalDisk (Map <String , String > volumeToDisconnect )
315385 {
386+ // as of now this is only relevant for iscsi targets
387+ s_logger .info ("Linstor: disconnectPhysicalDisk(Map<String, String> volumeToDisconnect) called?" );
316388 return false ;
317389 }
318390
319391 private Optional <ResourceWithVolumes > getResourceByPath (final List <ResourceWithVolumes > resources , String path ) {
320392 return resources .stream ()
321393 .filter (rsc -> rsc .getVolumes ().stream ()
322- .anyMatch (v -> v .getDevicePath (). equals ( path )))
394+ .anyMatch (v -> path . equals ( v .getDevicePath ())))
323395 .findFirst ();
324396 }
325397
@@ -340,46 +412,8 @@ public boolean disconnectPhysicalDiskByPath(String localPath)
340412 s_logger .debug ("Linstor: disconnectPhysicalDiskByPath " + localPath );
341413 final KVMStoragePool pool = optFirstPool .get ();
342414
343- s_logger .debug ("Linstor: Using storpool: " + pool .getUuid ());
344- final DevelopersApi api = getLinstorAPI (pool );
345-
346- Optional <ResourceWithVolumes > optRsc ;
347- try {
348- List <ResourceWithVolumes > resources = api .viewResources (
349- Collections .singletonList (localNodeName ),
350- null ,
351- null ,
352- null ,
353- null ,
354- null );
355-
356- optRsc = getResourceByPath (resources , localPath );
357- } catch (ApiException apiEx ) {
358- // couldn't query linstor controller
359- s_logger .error (apiEx .getBestMessage ());
360- return false ;
361- }
362-
363- if (optRsc .isPresent ()) {
364- try {
365- Resource rsc = optRsc .get ();
366- ResourceDefinitionModify rdm = new ResourceDefinitionModify ();
367- rdm .deleteProps (Collections .singletonList ("DrbdOptions/Net/allow-two-primaries" ));
368- ApiCallRcList answers = api .resourceDefinitionModify (rsc .getName (), rdm );
369- if (answers .hasError ()) {
370- s_logger .error (
371- String .format ("Failed to remove 'allow-two-primaries' on %s: %s" ,
372- rsc .getName (), LinstorUtil .getBestErrorMessage (answers )));
373- // do not fail here as removing allow-two-primaries property isn't fatal
374- }
375- } catch (ApiException apiEx ){
376- s_logger .error (apiEx .getBestMessage ());
377- // do not fail here as removing allow-two-primaries property isn't fatal
378- }
379- return true ;
380- }
415+ return tryDisconnectLinstor (localPath , pool );
381416 }
382- s_logger .info ("Linstor: Couldn't find resource for this path: " + localPath );
383417 return false ;
384418 }
385419
0 commit comments