6060import com .linbit .linstor .api .model .VolumeDefinition ;
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
@@ -558,6 +604,56 @@ private boolean resourceSupportZeroBlocks(KVMStoragePool destPool, String resNam
558604 return false ;
559605 }
560606
607+ /**
608+ * Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
609+ * The initial systemvm template resource isn't created on the management server, but
610+ * we now need to know if the systemvm template is used, while copying.
611+ * @param disk
612+ * @return True if it is the systemvm template disk, else false.
613+ */
614+ private static boolean isSystemTemplate (KVMPhysicalDisk disk ) {
615+ Path diskPath = Paths .get (disk .getPath ());
616+ Path propFile = diskPath .getParent ().resolve ("template.properties" );
617+ if (Files .exists (propFile )) {
618+ java .util .Properties templateProps = new java .util .Properties ();
619+ try {
620+ templateProps .load (new FileInputStream (propFile .toFile ()));
621+ String desc = templateProps .getProperty ("description" );
622+ if (desc .startsWith ("SystemVM Template" )) {
623+ return true ;
624+ }
625+ } catch (IOException e ) {
626+ return false ;
627+ }
628+ }
629+ return false ;
630+ }
631+
632+ /**
633+ * Conditionally sets the correct aux properties for templates or basic resources.
634+ * @param api
635+ * @param srcDisk
636+ * @param destPool
637+ * @param name
638+ */
639+ private void setRscDfnAuxProperties (
640+ DevelopersApi api , KVMPhysicalDisk srcDisk , KVMStoragePool destPool , String name ) {
641+ // if it is the initial systemvm disk copy, we need to apply the _cs-template-for property.
642+ if (isSystemTemplate (srcDisk )) {
643+ applyAuxProps (api , name , "SystemVM Template" , null );
644+ LinstorStoragePool linPool = (LinstorStoragePool ) destPool ;
645+ final String rscName = getLinstorRscName (name );
646+ try {
647+ LinstorUtil .setAuxTemplateForProperty (api , rscName , linPool .getResourceGroup ());
648+ } catch (ApiException apiExc ) {
649+ s_logger .error (String .format ("Error setting aux template for property for %s" , rscName ));
650+ logLinstorAnswers (apiExc .getApiCallRcList ());
651+ }
652+ } else {
653+ applyAuxProps (api , name , srcDisk .getDispName (), srcDisk .getVmName ());
654+ }
655+ }
656+
561657 @ Override
562658 public KVMPhysicalDisk copyPhysicalDisk (KVMPhysicalDisk disk , String name , KVMStoragePool destPools , int timeout , byte [] srcPassphrase , byte [] destPassphrase , Storage .ProvisioningType provisioningType )
563659 {
@@ -571,15 +667,14 @@ public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMSt
571667 name , QemuImg .PhysicalDiskFormat .RAW , provisioningType , disk .getVirtualSize (), null );
572668
573669 final DevelopersApi api = getLinstorAPI (destPools );
574- applyAuxProps (api , name , disk . getDispName (), disk . getVmName () );
670+ setRscDfnAuxProperties (api , disk , destPools , name );
575671
576672 s_logger .debug (String .format ("Linstor.copyPhysicalDisk: dstPath: %s" , dstDisk .getPath ()));
577673 final QemuImgFile destFile = new QemuImgFile (dstDisk .getPath ());
578674 destFile .setFormat (dstDisk .getFormat ());
579675 destFile .setSize (disk .getVirtualSize ());
580676
581- boolean zeroedDevice = resourceSupportZeroBlocks (destPools , LinstorUtil .RSC_PREFIX + name );
582-
677+ boolean zeroedDevice = resourceSupportZeroBlocks (destPools , getLinstorRscName (name ));
583678 try {
584679 final QemuImg qemu = new QemuImg (timeout , zeroedDevice , true );
585680 qemu .convert (srcFile , destFile );
0 commit comments