2121import com .linbit .linstor .api .DevelopersApi ;
2222import com .linbit .linstor .api .model .ApiCallRc ;
2323import com .linbit .linstor .api .model .ApiCallRcList ;
24+ import com .linbit .linstor .api .model .Properties ;
2425import com .linbit .linstor .api .model .ResourceDefinition ;
2526import com .linbit .linstor .api .model .ResourceDefinitionCloneRequest ;
2627import com .linbit .linstor .api .model .ResourceDefinitionCloneStarted ;
2728import com .linbit .linstor .api .model .ResourceDefinitionCreate ;
29+ import com .linbit .linstor .api .model .ResourceDefinitionModify ;
2830import com .linbit .linstor .api .model .ResourceGroupSpawn ;
2931import com .linbit .linstor .api .model .ResourceWithVolumes ;
3032import com .linbit .linstor .api .model .Snapshot ;
3133import com .linbit .linstor .api .model .SnapshotRestore ;
34+ import com .linbit .linstor .api .model .VolumeDefinition ;
3235import com .linbit .linstor .api .model .VolumeDefinitionModify ;
3336
3437import javax .annotation .Nonnull ;
3538import javax .inject .Inject ;
39+
40+ import java .util .Arrays ;
3641import java .util .Collections ;
3742import java .util .HashMap ;
3843import java .util .List ;
3944import java .util .Map ;
45+ import java .util .Objects ;
4046
4147import com .cloud .agent .api .Answer ;
4248import com .cloud .agent .api .storage .ResizeVolumeAnswer ;
@@ -242,14 +248,17 @@ public void deleteAsync(DataStore dataStore, DataObject dataObject, AsyncComplet
242248 deleteResourceDefinition (storagePool , rscName );
243249
244250 long usedBytes = storagePool .getUsedBytes ();
245- long capacityIops = storagePool .getCapacityIops ();
251+ Long capacityIops = storagePool .getCapacityIops ();
246252
247- usedBytes -= volumeInfo .getSize ();
248- if (volumeInfo .getMaxIops () != null )
249- capacityIops += volumeInfo .getMaxIops ();
253+ if (capacityIops != null )
254+ {
255+ if (volumeInfo .getMaxIops () != null )
256+ capacityIops += volumeInfo .getMaxIops ();
257+ storagePool .setCapacityIops (Math .max (0 , capacityIops ));
258+ }
250259
260+ usedBytes -= volumeInfo .getSize ();
251261 storagePool .setUsedBytes (Math .max (0 , usedBytes ));
252- storagePool .setCapacityIops (Math .max (0 , capacityIops ));
253262
254263 _storagePoolDao .update (storagePoolId , storagePool );
255264 }
@@ -325,6 +334,72 @@ private String getDeviceName(DevelopersApi linstorApi, String rscName) throws Ap
325334 }
326335 }
327336
337+ private void applyQoSSettings (StoragePoolVO storagePool , DevelopersApi api , String rscName , Long maxIops )
338+ throws ApiException
339+ {
340+ Long currentQosIops = null ;
341+ List <VolumeDefinition > vlmDfns = api .volumeDefinitionList (rscName , null , null );
342+ if (!vlmDfns .isEmpty ())
343+ {
344+ Properties props = vlmDfns .get (0 ).getProps ();
345+ long iops = Long .parseLong (props .getOrDefault ("sys/fs/blkio_throttle_write_iops" , "0" ));
346+ currentQosIops = iops > 0 ? iops : null ;
347+ }
348+
349+ if (!Objects .equals (maxIops , currentQosIops ))
350+ {
351+ VolumeDefinitionModify vdm = new VolumeDefinitionModify ();
352+ if (maxIops != null )
353+ {
354+ Properties props = new Properties ();
355+ props .put ("sys/fs/blkio_throttle_read_iops" , "" + maxIops );
356+ props .put ("sys/fs/blkio_throttle_write_iops" , "" + maxIops );
357+ vdm .overrideProps (props );
358+ s_logger .info ("Apply qos setting: " + maxIops + " to " + rscName );
359+ }
360+ else
361+ {
362+ s_logger .info ("Remove QoS setting for " + rscName );
363+ vdm .deleteProps (Arrays .asList ("sys/fs/blkio_throttle_read_iops" , "sys/fs/blkio_throttle_write_iops" ));
364+ }
365+ ApiCallRcList answers = api .volumeDefinitionModify (rscName , 0 , vdm );
366+ checkLinstorAnswersThrow (answers );
367+
368+ Long capacityIops = storagePool .getCapacityIops ();
369+ if (capacityIops != null )
370+ {
371+ long vcIops = currentQosIops != null ? currentQosIops * -1 : 0 ;
372+ long vMaxIops = maxIops != null ? maxIops : 0 ;
373+ long newIops = vcIops + vMaxIops ;
374+ capacityIops -= newIops ;
375+ s_logger .info ("Current storagepool " + storagePool .getName () + " iops capacity: " + capacityIops );
376+ storagePool .setCapacityIops (Math .max (0 , capacityIops ));
377+ _storagePoolDao .update (storagePool .getId (), storagePool );
378+ }
379+ }
380+ }
381+
382+ private void applyAuxProps (DevelopersApi api , String rscName , String dispName , String vmName )
383+ throws ApiException
384+ {
385+ ResourceDefinitionModify rdm = new ResourceDefinitionModify ();
386+ Properties props = new Properties ();
387+ if (dispName != null )
388+ {
389+ props .put ("Aux/cs-name" , dispName );
390+ }
391+ if (vmName != null )
392+ {
393+ props .put ("Aux/cs-vm-name" , vmName );
394+ }
395+ if (!props .isEmpty ())
396+ {
397+ rdm .setOverrideProps (props );
398+ ApiCallRcList answers = api .resourceDefinitionModify (rscName , rdm );
399+ checkLinstorAnswersThrow (answers );
400+ }
401+ }
402+
328403 private String createResource (VolumeInfo vol , StoragePoolVO storagePoolVO )
329404 {
330405 DevelopersApi linstorApi = LinstorUtil .getLinstorAPI (storagePoolVO .getHostAddress ());
@@ -338,10 +413,13 @@ private String createResource(VolumeInfo vol, StoragePoolVO storagePoolVO)
338413
339414 try
340415 {
341- s_logger .debug ("Linstor: Spawn resource " + rscName );
416+ s_logger .info ("Linstor: Spawn resource " + rscName );
342417 ApiCallRcList answers = linstorApi .resourceGroupSpawn (rscGrp , rscGrpSpawn );
343418 checkLinstorAnswersThrow (answers );
344419
420+ applyAuxProps (linstorApi , rscName , vol .getName (), vol .getAttachedVmName ());
421+ applyQoSSettings (storagePoolVO , linstorApi , rscName , vol .getMaxIops ());
422+
345423 return getDeviceName (linstorApi , rscName );
346424 } catch (ApiException apiEx )
347425 {
@@ -361,7 +439,7 @@ private String cloneResource(long csCloneId, VolumeInfo volumeInfo, StoragePoolV
361439 final DevelopersApi linstorApi = LinstorUtil .getLinstorAPI (storagePoolVO .getHostAddress ());
362440
363441 try {
364- s_logger .debug ("Clone resource definition " + cloneRes + " to " + rscName );
442+ s_logger .info ("Clone resource definition " + cloneRes + " to " + rscName );
365443 ResourceDefinitionCloneRequest cloneRequest = new ResourceDefinitionCloneRequest ();
366444 cloneRequest .setName (rscName );
367445 ResourceDefinitionCloneStarted cloneStarted = linstorApi .resourceDefinitionClone (
@@ -373,6 +451,10 @@ private String cloneResource(long csCloneId, VolumeInfo volumeInfo, StoragePoolV
373451 throw new CloudRuntimeException ("Clone for resource " + rscName + " failed." );
374452 }
375453
454+ s_logger .info ("Clone resource definition " + cloneRes + " to " + rscName + " finished" );
455+ applyAuxProps (linstorApi , rscName , volumeInfo .getName (), volumeInfo .getAttachedVmName ());
456+ applyQoSSettings (storagePoolVO , linstorApi , rscName , volumeInfo .getMaxIops ());
457+
376458 return getDeviceName (linstorApi , rscName );
377459 } catch (ApiException apiEx ) {
378460 s_logger .error ("Linstor: ApiEx - " + apiEx .getMessage ());
@@ -413,10 +495,13 @@ private String createResourceFromSnapshot(long csSnapshotId, String rscName, Sto
413495 checkLinstorAnswersThrow (answers );
414496
415497 // restore snapshot to new resource
416- s_logger .debug ("Restore resource from snapshot: " + cloneRes + ":" + snapName );
498+ s_logger .info ("Restore resource from snapshot: " + cloneRes + ":" + snapName );
417499 answers = linstorApi .resourceSnapshotRestore (cloneRes , snapName , snapshotRestore );
418500 checkLinstorAnswersThrow (answers );
419501
502+ applyAuxProps (linstorApi , rscName , volumeVO .getName (), null );
503+ applyQoSSettings (storagePoolVO , linstorApi , rscName , volumeVO .getMaxIops ());
504+
420505 return getDeviceName (linstorApi , rscName );
421506 } catch (ApiException apiEx ) {
422507 s_logger .error ("Linstor: ApiEx - " + apiEx .getMessage ());
@@ -608,12 +693,11 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As
608693 }
609694
610695 private CreateCmdResult notifyResize (
611- DataObject data ,
696+ VolumeObject vol ,
612697 long oldSize ,
613698 ResizeVolumePayload resizeParameter )
614699 {
615- VolumeObject vol = (VolumeObject ) data ;
616- StoragePool pool = (StoragePool ) data .getDataStore ();
700+ StoragePool pool = (StoragePool ) vol .getDataStore ();
617701
618702 ResizeVolumeCommand resizeCmd =
619703 new ResizeVolumeCommand (vol .getPath (), new StorageFilerTO (pool ), oldSize , resizeParameter .newSize , resizeParameter .shrinkOk ,
@@ -642,7 +726,7 @@ private CreateCmdResult notifyResize(
642726 public void resize (DataObject data , AsyncCompletionCallback <CreateCmdResult > callback )
643727 {
644728 final VolumeObject vol = (VolumeObject ) data ;
645- final StoragePool pool = ( StoragePool ) data .getDataStore ();
729+ final StoragePoolVO pool = _storagePoolDao . findById ( data .getDataStore (). getId () );
646730 final DevelopersApi api = LinstorUtil .getLinstorAPI (pool .getHostAddress ());
647731 final ResizeVolumePayload resizeParameter = (ResizeVolumePayload ) vol .getpayload ();
648732
@@ -654,6 +738,14 @@ public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> cal
654738 dfm .setSizeKib (resizeParameter .newSize / 1024 );
655739 try
656740 {
741+ applyQoSSettings (pool , api , rscName , resizeParameter .newMaxIops );
742+ {
743+ final VolumeVO volume = _volumeDao .findById (vol .getId ());
744+ volume .setMinIops (resizeParameter .newMinIops );
745+ volume .setMaxIops (resizeParameter .newMaxIops );
746+ _volumeDao .update (volume .getId (), volume );
747+ }
748+
657749 ApiCallRcList answers = api .volumeDefinitionModify (rscName , 0 , dfm );
658750 if (answers .hasError ())
659751 {
@@ -680,7 +772,7 @@ public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> cal
680772 } else
681773 {
682774 // notify guests
683- result = notifyResize (data , oldSize , resizeParameter );
775+ result = notifyResize (vol , oldSize , resizeParameter );
684776 }
685777
686778 callback .complete (result );
0 commit comments