6060import org .libvirt .LibvirtException ;
6161
6262import java .io .File ;
63+ import java .io .FileInputStream ;
64+ import java .io .IOException ;
65+ import java .nio .file .Files ;
66+ import java .nio .file .Path ;
67+ import java .nio .file .Paths ;
6368
6469@ StorageAdaptorInfo (storagePoolType =Storage .StoragePoolType .Linstor )
6570public class LinstorStorageAdaptor implements StorageAdaptor {
@@ -198,10 +203,10 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
198203 final DevelopersApi api = getLinstorAPI (pool );
199204
200205 try {
201- List < ResourceDefinition > definitionList = api . resourceDefinitionList (
202- Collections . singletonList ( rscName ), null , null , null );
206+ ResourceDefinition resourceDefinition = LinstorUtil . findResourceDefinition (
207+ api , rscName , lpool . getResourceGroup () );
203208
204- if (definitionList . isEmpty () ) {
209+ if (resourceDefinition == null ) {
205210 ResourceGroupSpawn rgSpawn = new ResourceGroupSpawn ();
206211 rgSpawn .setResourceDefinitionName (rscName );
207212 rgSpawn .addVolumeSizesItem (size / 1024 ); // linstor uses KiB
@@ -211,22 +216,28 @@ public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, Qemu
211216 handleLinstorApiAnswers (answers , "Linstor: Unable to spawn resource." );
212217 }
213218
219+ String foundRscName = resourceDefinition != null ? resourceDefinition .getName () : rscName ;
220+
214221 // query linstor for the device path
215222 List <ResourceWithVolumes > resources = api .viewResources (
216223 Collections .emptyList (),
217- Collections .singletonList (rscName ),
224+ Collections .singletonList (foundRscName ),
218225 Collections .emptyList (),
219226 null ,
220227 null ,
221228 null );
222229
223- makeResourceAvailable (api , rscName , false );
230+ makeResourceAvailable (api , foundRscName , false );
224231
225232 if (!resources .isEmpty () && !resources .get (0 ).getVolumes ().isEmpty ()) {
226233 final String devPath = resources .get (0 ).getVolumes ().get (0 ).getDevicePath ();
227234 s_logger .info ("Linstor: Created drbd device: " + devPath );
228235 final KVMPhysicalDisk kvmDisk = new KVMPhysicalDisk (devPath , name , pool );
229236 kvmDisk .setFormat (QemuImg .PhysicalDiskFormat .RAW );
237+ long allocatedKib = resources .get (0 ).getVolumes ().get (0 ).getAllocatedSizeKib () != null ?
238+ resources .get (0 ).getVolumes ().get (0 ).getAllocatedSizeKib () : 0 ;
239+ kvmDisk .setSize (allocatedKib >= 0 ? allocatedKib * 1024 : 0 );
240+ kvmDisk .setVirtualSize (size );
230241 return kvmDisk ;
231242 } else {
232243 s_logger .error ("Linstor: viewResources didn't return resources or volumes." );
@@ -470,21 +481,56 @@ public boolean disconnectPhysicalDiskByPath(String localPath)
470481 return false ;
471482 }
472483
484+ /**
485+ * Decrements the aux property key for template resource and deletes or just deletes if not template resource.
486+ * @param api
487+ * @param rscName
488+ * @param rscGrpName
489+ * @return
490+ * @throws ApiException
491+ */
492+ private boolean deRefOrDeleteResource (DevelopersApi api , String rscName , String rscGrpName ) throws ApiException {
493+ boolean deleted = false ;
494+ List <ResourceDefinition > existingRDs = LinstorUtil .getRDListStartingWith (api , rscName );
495+ for (ResourceDefinition rd : existingRDs ) {
496+ int expectedProps = 0 ; // if it is a non template resource, we don't expect any _cs-template-for- prop
497+ String propKey = LinstorUtil .getTemplateForAuxPropKey (rscGrpName );
498+ if (rd .getProps ().containsKey (propKey )) {
499+ ResourceDefinitionModify rdm = new ResourceDefinitionModify ();
500+ rdm .deleteProps (Collections .singletonList (propKey ));
501+ api .resourceDefinitionModify (rd .getName (), rdm );
502+ expectedProps = 1 ;
503+ }
504+
505+ // if there is only one template-for property left for templates, the template isn't needed anymore
506+ // or if it isn't a template anyway, it will not have this Aux property
507+ // _cs-template-for- poperties work like a ref-count.
508+ if (rd .getProps ().keySet ().stream ()
509+ .filter (key -> key .startsWith ("Aux/" + LinstorUtil .CS_TEMPLATE_FOR_PREFIX ))
510+ .count () == expectedProps ) {
511+ ApiCallRcList answers = api .resourceDefinitionDelete (rd .getName ());
512+ checkLinstorAnswersThrow (answers );
513+ deleted = true ;
514+ }
515+ }
516+ return deleted ;
517+ }
518+
473519 @ Override
474520 public boolean deletePhysicalDisk (String name , KVMStoragePool pool , Storage .ImageFormat format )
475521 {
476522 s_logger .debug ("Linstor: deletePhysicalDisk " + name );
477523 final DevelopersApi api = getLinstorAPI (pool );
524+ final String rscName = getLinstorRscName (name );
525+ final LinstorStoragePool linstorPool = (LinstorStoragePool ) pool ;
526+ String rscGrpName = linstorPool .getResourceGroup ();
478527
479528 try {
480- final String rscName = getLinstorRscName (name );
481- s_logger .debug ("Linstor: delete resource definition " + rscName );
482- ApiCallRcList answers = api .resourceDefinitionDelete (rscName );
483- handleLinstorApiAnswers (answers , "Linstor: Unable to delete resource definition " + rscName );
529+ return deRefOrDeleteResource (api , rscName , rscGrpName );
484530 } catch (ApiException apiEx ) {
531+ s_logger .error ("Linstor: ApiEx - " + apiEx .getMessage ());
485532 throw new CloudRuntimeException (apiEx .getBestMessage (), apiEx );
486533 }
487- return true ;
488534 }
489535
490536 @ Override
@@ -552,6 +598,56 @@ private boolean resourceSupportZeroBlocks(KVMStoragePool destPool, String resNam
552598 return false ;
553599 }
554600
601+ /**
602+ * Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
603+ * The initial systemvm template resource isn't created on the management server, but
604+ * we now need to know if the systemvm template is used, while copying.
605+ * @param disk
606+ * @return True if it is the systemvm template disk, else false.
607+ */
608+ private static boolean isSystemTemplate (KVMPhysicalDisk disk ) {
609+ Path diskPath = Paths .get (disk .getPath ());
610+ Path propFile = diskPath .getParent ().resolve ("template.properties" );
611+ if (Files .exists (propFile )) {
612+ java .util .Properties templateProps = new java .util .Properties ();
613+ try {
614+ templateProps .load (new FileInputStream (propFile .toFile ()));
615+ String desc = templateProps .getProperty ("description" );
616+ if (desc .startsWith ("SystemVM Template" )) {
617+ return true ;
618+ }
619+ } catch (IOException e ) {
620+ return false ;
621+ }
622+ }
623+ return false ;
624+ }
625+
626+ /**
627+ * Conditionally sets the correct aux properties for templates or basic resources.
628+ * @param api
629+ * @param srcDisk
630+ * @param destPool
631+ * @param name
632+ */
633+ private void setRscDfnAuxProperties (
634+ DevelopersApi api , KVMPhysicalDisk srcDisk , KVMStoragePool destPool , String name ) {
635+ // if it is the initial systemvm disk copy, we need to apply the _cs-template-for property.
636+ if (isSystemTemplate (srcDisk )) {
637+ applyAuxProps (api , name , "SystemVM Template" , null );
638+ LinstorStoragePool linPool = (LinstorStoragePool ) destPool ;
639+ final String rscName = getLinstorRscName (name );
640+ try {
641+ LinstorUtil .setAuxTemplateForProperty (api , rscName , linPool .getResourceGroup ());
642+ } catch (ApiException apiExc ) {
643+ s_logger .error (String .format ("Error setting aux template for property for %s" , rscName ));
644+ logLinstorAnswers (apiExc .getApiCallRcList ());
645+ }
646+ } else {
647+ applyAuxProps (api , name , srcDisk .getDispName (), srcDisk .getVmName ());
648+ }
649+ }
650+
555651 @ Override
556652 public KVMPhysicalDisk copyPhysicalDisk (KVMPhysicalDisk disk , String name , KVMStoragePool destPools , int timeout )
557653 {
@@ -566,7 +662,7 @@ public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMSt
566662 name , QemuImg .PhysicalDiskFormat .RAW , Storage .ProvisioningType .FAT , disk .getVirtualSize ());
567663
568664 final DevelopersApi api = getLinstorAPI (destPools );
569- applyAuxProps (api , name , disk . getDispName (), disk . getVmName () );
665+ setRscDfnAuxProperties (api , disk , destPools , name );
570666
571667 s_logger .debug (String .format ("Linstor.copyPhysicalDisk: dstPath: %s" , dstDisk .getPath ()));
572668 final QemuImgFile destFile = new QemuImgFile (dstDisk .getPath ());
0 commit comments