6161import com .linbit .linstor .api .model .VolumeDefinition ;
6262
6363import java .io .File ;
64+ import java .io .FileInputStream ;
65+ import java .io .IOException ;
66+ import java .nio .file .Files ;
67+ import java .nio .file .Path ;
68+ import java .nio .file .Paths ;
6469
6570public class LinstorStorageAdaptor implements StorageAdaptor {
6671 protected Logger logger = LogManager .getLogger (getClass ());
@@ -202,10 +207,10 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
202207 final DevelopersApi api = getLinstorAPI (pool );
203208
204209 try {
205- List < ResourceDefinition > definitionList = api . resourceDefinitionList (
206- Collections . singletonList ( rscName ), null , null , null );
210+ ResourceDefinition resourceDefinition = LinstorUtil . findResourceDefinition (
211+ api , rscName , lpool . getResourceGroup () );
207212
208- if (definitionList . isEmpty () ) {
213+ if (resourceDefinition == null ) {
209214 ResourceGroupSpawn rgSpawn = new ResourceGroupSpawn ();
210215 rgSpawn .setResourceDefinitionName (rscName );
211216 rgSpawn .addVolumeSizesItem (size / 1024 ); // linstor uses KiB
@@ -215,22 +220,28 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
215220 handleLinstorApiAnswers (answers , "Linstor: Unable to spawn resource." );
216221 }
217222
223+ String foundRscName = resourceDefinition != null ? resourceDefinition .getName () : rscName ;
224+
218225 // query linstor for the device path
219226 List <ResourceWithVolumes > resources = api .viewResources (
220227 Collections .emptyList (),
221- Collections .singletonList (rscName ),
228+ Collections .singletonList (foundRscName ),
222229 Collections .emptyList (),
223230 null ,
224231 null ,
225232 null );
226233
227- makeResourceAvailable (api , rscName , false );
234+ makeResourceAvailable (api , foundRscName , false );
228235
229236 if (!resources .isEmpty () && !resources .get (0 ).getVolumes ().isEmpty ()) {
230237 final String devPath = resources .get (0 ).getVolumes ().get (0 ).getDevicePath ();
231238 logger .info ("Linstor: Created drbd device: " + devPath );
232239 final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk (devPath , name , pool );
233240 kvmDisk .setFormat (QemuImg .PhysicalDiskFormat .RAW );
241+ long allocatedKib = resources .get (0 ).getVolumes ().get (0 ).getAllocatedSizeKib () != null ?
242+ resources .get (0 ).getVolumes ().get (0 ).getAllocatedSizeKib () : 0 ;
243+ kvmDisk .setSize (allocatedKib >= 0 ? allocatedKib * 1024 : 0 );
244+ kvmDisk .setVirtualSize (size );
234245 return kvmDisk ;
235246 } else {
236247 logger .error ("Linstor: viewResources didn't return resources or volumes." );
@@ -473,21 +484,56 @@ public boolean disconnectPhysicalDiskByPath(String localPath)
473484 return false ;
474485 }
475486
487+ /**
488+ * Decrements the aux property key for template resource and deletes or just deletes if not template resource.
489+ * @param api
490+ * @param rscName
491+ * @param rscGrpName
492+ * @return
493+ * @throws ApiException
494+ */
495+ private boolean deRefOrDeleteResource (DevelopersApi api , String rscName , String rscGrpName ) throws ApiException {
496+ boolean deleted = false ;
497+ List <ResourceDefinition > existingRDs = LinstorUtil .getRDListStartingWith (api , rscName );
498+ for (ResourceDefinition rd : existingRDs ) {
499+ int expectedProps = 0 ; // if it is a non template resource, we don't expect any _cs-template-for- prop
500+ String propKey = LinstorUtil .getTemplateForAuxPropKey (rscGrpName );
501+ if (rd .getProps ().containsKey (propKey )) {
502+ ResourceDefinitionModify rdm = new ResourceDefinitionModify ();
503+ rdm .deleteProps (Collections .singletonList (propKey ));
504+ api .resourceDefinitionModify (rd .getName (), rdm );
505+ expectedProps = 1 ;
506+ }
507+
508+ // if there is only one template-for property left for templates, the template isn't needed anymore
509+ // or if it isn't a template anyway, it will not have this Aux property
510+ // _cs-template-for- properties work like a ref-count.
511+ if (rd .getProps ().keySet ().stream ()
512+ .filter (key -> key .startsWith ("Aux/" + LinstorUtil .CS_TEMPLATE_FOR_PREFIX ))
513+ .count () == expectedProps ) {
514+ ApiCallRcList answers = api .resourceDefinitionDelete (rd .getName ());
515+ checkLinstorAnswersThrow (answers );
516+ deleted = true ;
517+ }
518+ }
519+ return deleted ;
520+ }
521+
476522 @ Override
477523 public boolean deletePhysicalDisk (String name , KVMStoragePool pool , Storage .ImageFormat format )
478524 {
479525 logger .debug ("Linstor: deletePhysicalDisk " + name );
480526 final DevelopersApi api = getLinstorAPI (pool );
527+ final String rscName = getLinstorRscName (name );
528+ final LinstorStoragePool linstorPool = (LinstorStoragePool ) pool ;
529+ String rscGrpName = linstorPool .getResourceGroup ();
481530
482531 try {
483- final String rscName = getLinstorRscName (name );
484- logger .debug ("Linstor: delete resource definition " + rscName );
485- ApiCallRcList answers = api .resourceDefinitionDelete (rscName );
486- handleLinstorApiAnswers (answers , "Linstor: Unable to delete resource definition " + rscName );
532+ return deRefOrDeleteResource (api , rscName , rscGrpName );
487533 } catch (ApiException apiEx ) {
534+ logger .error ("Linstor: ApiEx - " + apiEx .getMessage ());
488535 throw new CloudRuntimeException (apiEx .getBestMessage (), apiEx );
489536 }
490- return true ;
491537 }
492538
493539 @ Override
@@ -561,6 +607,56 @@ private boolean resourceSupportZeroBlocks(KVMStoragePool destPool, String resNam
561607 return false ;
562608 }
563609
610+ /**
611+ * Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
612+ * The initial systemvm template resource isn't created on the management server, but
613+ * we now need to know if the systemvm template is used, while copying.
614+ * @param disk
615+ * @return True if it is the systemvm template disk, else false.
616+ */
617+ private static boolean isSystemTemplate (KVMPhysicalDisk disk ) {
618+ Path diskPath = Paths .get (disk .getPath ());
619+ Path propFile = diskPath .getParent ().resolve ("template.properties" );
620+ if (Files .exists (propFile )) {
621+ java .util .Properties templateProps = new java .util .Properties ();
622+ try {
623+ templateProps .load (new FileInputStream (propFile .toFile ()));
624+ String desc = templateProps .getProperty ("description" );
625+ if (desc .startsWith ("SystemVM Template" )) {
626+ return true ;
627+ }
628+ } catch (IOException e ) {
629+ return false ;
630+ }
631+ }
632+ return false ;
633+ }
634+
635+ /**
636+ * Conditionally sets the correct aux properties for templates or basic resources.
637+ * @param api
638+ * @param srcDisk
639+ * @param destPool
640+ * @param name
641+ */
642+ private void setRscDfnAuxProperties (
643+ DevelopersApi api , KVMPhysicalDisk srcDisk , KVMStoragePool destPool , String name ) {
644+ // if it is the initial systemvm disk copy, we need to apply the _cs-template-for property.
645+ if (isSystemTemplate (srcDisk )) {
646+ applyAuxProps (api , name , "SystemVM Template" , null );
647+ LinstorStoragePool linPool = (LinstorStoragePool ) destPool ;
648+ final String rscName = getLinstorRscName (name );
649+ try {
650+ LinstorUtil .setAuxTemplateForProperty (api , rscName , linPool .getResourceGroup ());
651+ } catch (ApiException apiExc ) {
652+ logger .error ("Error setting aux template for property for {}" , rscName );
653+ logLinstorAnswers (apiExc .getApiCallRcList ());
654+ }
655+ } else {
656+ applyAuxProps (api , name , srcDisk .getDispName (), srcDisk .getVmName ());
657+ }
658+ }
659+
564660 @ Override
565661 public KVMPhysicalDisk copyPhysicalDisk (KVMPhysicalDisk disk , String name , KVMStoragePool destPools , int timeout , byte [] srcPassphrase , byte [] destPassphrase , Storage .ProvisioningType provisioningType )
566662 {
@@ -574,15 +670,14 @@ public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMSt
574670 name , QemuImg .PhysicalDiskFormat .RAW , provisioningType , disk .getVirtualSize (), null );
575671
576672 final DevelopersApi api = getLinstorAPI (destPools );
577- applyAuxProps (api , name , disk . getDispName (), disk . getVmName () );
673+ setRscDfnAuxProperties (api , disk , destPools , name );
578674
579675 logger .debug ("Linstor.copyPhysicalDisk: dstPath: {}" , dstDisk .getPath ());
580676 final QemuImgFile destFile = new QemuImgFile (dstDisk .getPath ());
581677 destFile .setFormat (dstDisk .getFormat ());
582678 destFile .setSize (disk .getVirtualSize ());
583679
584- boolean zeroedDevice = resourceSupportZeroBlocks (destPools , LinstorUtil .RSC_PREFIX + name );
585-
680+ boolean zeroedDevice = resourceSupportZeroBlocks (destPools , getLinstorRscName (name ));
586681 try {
587682 final QemuImg qemu = new QemuImg (timeout , zeroedDevice , true );
588683 qemu .convert (srcFile , destFile );
@@ -735,4 +830,4 @@ public boolean isNodeOnline(LinstorStoragePool pool, String nodeName) {
735830 throw new CloudRuntimeException (apiEx .getBestMessage (), apiEx );
736831 }
737832 }
738- }
833+ }
0 commit comments