@@ -216,6 +216,11 @@ public class ExtensionsManagerImpl extends ManagerBase implements ExtensionsMana
216216 @ Inject
217217 AccountService accountService ;
218218
219+ // Map of in-built extension names and their reserved resource details that shouldn't be accessible to end-users
220+ protected static final Map <String , List <String >> INBUILT_RESERVED_RESOURCE_DETAILS = Map .of (
221+ "proxmox" , List .of ("proxmox_vmid" )
222+ );
223+
219224 private ScheduledExecutorService extensionPathStateCheckExecutor ;
220225
221226 protected String getDefaultExtensionRelativePath (String name ) {
@@ -563,6 +568,25 @@ protected void checkExtensionPathState(Extension extension, List<ManagementServe
563568 updateExtensionPathReady (extension , true );
564569 }
565570
571+ protected void addInbuiltExtensionReservedResourceDetails (long extensionId , List <String > reservedResourceDetails ) {
572+ ExtensionVO vo = extensionDao .findById (extensionId );
573+ if (vo == null || vo .isUserDefined ()) {
574+ return ;
575+ }
576+ String lowerName = StringUtils .defaultString (vo .getName ()).toLowerCase ();
577+ Optional <Map .Entry <String , List <String >>> match = INBUILT_RESERVED_RESOURCE_DETAILS .entrySet ().stream ()
578+ .filter (e -> lowerName .contains (e .getKey ().toLowerCase ()))
579+ .findFirst ();
580+ if (match .isPresent ()) {
581+ Set <String > existing = new HashSet <>(reservedResourceDetails );
582+ for (String detailKey : match .get ().getValue ()) {
583+ if (existing .add (detailKey )) {
584+ reservedResourceDetails .add (detailKey );
585+ }
586+ }
587+ }
588+ }
589+
566590 @ Override
567591 public String getExtensionsPath () {
568592 return externalProvisioner .getExtensionsPath ();
@@ -577,6 +601,7 @@ public Extension createExtension(CreateExtensionCmd cmd) {
577601 String relativePath = cmd .getPath ();
578602 final Boolean orchestratorRequiresPrepareVm = cmd .isOrchestratorRequiresPrepareVm ();
579603 final String stateStr = cmd .getState ();
604+ final String reservedResourceDetails = cmd .getReservedResourceDetails ();
580605 ExtensionVO extensionByName = extensionDao .findByName (name );
581606 if (extensionByName != null ) {
582607 throw new CloudRuntimeException ("Extension by name already exists" );
@@ -624,6 +649,10 @@ public Extension createExtension(CreateExtensionCmd cmd) {
624649 ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM , String .valueOf (orchestratorRequiresPrepareVm ),
625650 false ));
626651 }
652+ if (StringUtils .isNotBlank (reservedResourceDetails )) {
653+ detailsVOList .add (new ExtensionDetailsVO (extension .getId (),
654+ ApiConstants .RESERVED_RESOURCE_DETAILS , reservedResourceDetails , false ));
655+ }
627656 if (CollectionUtils .isNotEmpty (detailsVOList )) {
628657 extensionDetailsDao .saveDetails (detailsVOList );
629658 }
@@ -704,6 +733,7 @@ public Extension updateExtension(UpdateExtensionCmd cmd) {
704733 final String stateStr = cmd .getState ();
705734 final Map <String , String > details = cmd .getDetails ();
706735 final Boolean cleanupDetails = cmd .isCleanupDetails ();
736+ final String reservedResourceDetails = cmd .getReservedResourceDetails ();
707737 final ExtensionVO extensionVO = extensionDao .findById (id );
708738 if (extensionVO == null ) {
709739 throw new InvalidParameterValueException ("Failed to find the extension" );
@@ -732,7 +762,8 @@ public Extension updateExtension(UpdateExtensionCmd cmd) {
732762 throw new CloudRuntimeException (String .format ("Failed to updated the extension: %s" ,
733763 extensionVO .getName ()));
734764 }
735- updateExtensionsDetails (cleanupDetails , details , orchestratorRequiresPrepareVm , id );
765+ updateExtensionsDetails (cleanupDetails , details , orchestratorRequiresPrepareVm , reservedResourceDetails ,
766+ id );
736767 return extensionVO ;
737768 });
738769 if (StringUtils .isNotBlank (stateStr )) {
@@ -748,9 +779,11 @@ public Extension updateExtension(UpdateExtensionCmd cmd) {
748779 return result ;
749780 }
750781
751- protected void updateExtensionsDetails (Boolean cleanupDetails , Map <String , String > details , Boolean orchestratorRequiresPrepareVm , long id ) {
782+ protected void updateExtensionsDetails (Boolean cleanupDetails , Map <String , String > details ,
783+ Boolean orchestratorRequiresPrepareVm , String reservedResourceDetails , long id ) {
752784 final boolean needToUpdateAllDetails = Boolean .TRUE .equals (cleanupDetails ) || MapUtils .isNotEmpty (details );
753- if (!needToUpdateAllDetails && orchestratorRequiresPrepareVm == null ) {
785+ if (!needToUpdateAllDetails && orchestratorRequiresPrepareVm == null &&
786+ StringUtils .isBlank (reservedResourceDetails )) {
754787 return ;
755788 }
756789 if (needToUpdateAllDetails ) {
@@ -761,6 +794,9 @@ protected void updateExtensionsDetails(Boolean cleanupDetails, Map<String, Strin
761794 hiddenDetails .put (ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM ,
762795 String .valueOf (orchestratorRequiresPrepareVm ));
763796 }
797+ if (StringUtils .isNotBlank (reservedResourceDetails )) {
798+ hiddenDetails .put (ApiConstants .RESERVED_RESOURCE_DETAILS , reservedResourceDetails );
799+ }
764800 if (MapUtils .isNotEmpty (hiddenDetails )) {
765801 hiddenDetails .forEach ((key , value ) -> detailsVOList .add (
766802 new ExtensionDetailsVO (id , key , value , false )));
@@ -775,15 +811,29 @@ protected void updateExtensionsDetails(Boolean cleanupDetails, Map<String, Strin
775811 extensionDetailsDao .removeDetails (id );
776812 }
777813 } else {
778- ExtensionDetailsVO detailsVO = extensionDetailsDao .findDetail (id ,
779- ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM );
780- if (detailsVO == null ) {
781- extensionDetailsDao .persist (new ExtensionDetailsVO (id ,
782- ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM ,
783- String .valueOf (orchestratorRequiresPrepareVm ), false ));
784- } else if (Boolean .parseBoolean (detailsVO .getValue ()) != orchestratorRequiresPrepareVm ) {
785- detailsVO .setValue (String .valueOf (orchestratorRequiresPrepareVm ));
786- extensionDetailsDao .update (detailsVO .getId (), detailsVO );
814+ if (orchestratorRequiresPrepareVm != null ) {
815+ ExtensionDetailsVO detailsVO = extensionDetailsDao .findDetail (id ,
816+ ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM );
817+ if (detailsVO == null ) {
818+ extensionDetailsDao .persist (new ExtensionDetailsVO (id ,
819+ ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM ,
820+ String .valueOf (orchestratorRequiresPrepareVm ), false ));
821+ } else if (Boolean .parseBoolean (detailsVO .getValue ()) != orchestratorRequiresPrepareVm ) {
822+ detailsVO .setValue (String .valueOf (orchestratorRequiresPrepareVm ));
823+ extensionDetailsDao .update (detailsVO .getId (), detailsVO );
824+ }
825+ }
826+ if (StringUtils .isNotBlank (reservedResourceDetails )) {
827+ ExtensionDetailsVO detailsVO = extensionDetailsDao .findDetail (id ,
828+ ApiConstants .RESERVED_RESOURCE_DETAILS );
829+ if (detailsVO == null ) {
830+ extensionDetailsDao .persist (new ExtensionDetailsVO (id ,
831+ ApiConstants .RESERVED_RESOURCE_DETAILS ,
832+ reservedResourceDetails , false ));
833+ } else if (!reservedResourceDetails .equals (detailsVO .getValue ())) {
834+ detailsVO .setValue (reservedResourceDetails );
835+ extensionDetailsDao .update (detailsVO .getId (), detailsVO );
836+ }
787837 }
788838 }
789839 }
@@ -961,12 +1011,16 @@ public ExtensionResponse createExtensionResponse(Extension extension,
9611011 hiddenDetails = extensionDetails .second ();
9621012 } else {
9631013 hiddenDetails = extensionDetailsDao .listDetailsKeyPairs (extension .getId (),
964- List .of (ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM ));
1014+ List .of (ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM ,
1015+ ApiConstants .RESERVED_RESOURCE_DETAILS ));
9651016 }
9661017 if (hiddenDetails .containsKey (ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM )) {
9671018 response .setOrchestratorRequiresPrepareVm (Boolean .parseBoolean (
9681019 hiddenDetails .get (ApiConstants .ORCHESTRATOR_REQUIRES_PREPARE_VM )));
9691020 }
1021+ if (hiddenDetails .containsKey (ApiConstants .RESERVED_RESOURCE_DETAILS )) {
1022+ response .setReservedResourceDetails (hiddenDetails .get (ApiConstants .RESERVED_RESOURCE_DETAILS ));
1023+ }
9701024 response .setObjectName (Extension .class .getSimpleName ().toLowerCase ());
9711025 return response ;
9721026 }
@@ -1605,6 +1659,24 @@ public Extension getExtensionForCluster(long clusterId) {
16051659 return extensionDao .findById (extensionId );
16061660 }
16071661
1662+ @ Override
1663+ public List <String > getExtensionReservedResourceDetails (long extensionId ) {
1664+ ExtensionDetailsVO detailsVO = extensionDetailsDao .findDetail (extensionId ,
1665+ ApiConstants .RESERVED_RESOURCE_DETAILS );
1666+ if (detailsVO == null || !StringUtils .isNotBlank (detailsVO .getValue ())) {
1667+ return Collections .emptyList ();
1668+ }
1669+ List <String > reservedDetails = new ArrayList <>();
1670+ String [] parts = detailsVO .getValue ().split ("," );
1671+ for (String part : parts ) {
1672+ if (StringUtils .isNotBlank (part )) {
1673+ reservedDetails .add (part .trim ());
1674+ }
1675+ }
1676+ addInbuiltExtensionReservedResourceDetails (extensionId , reservedDetails );
1677+ return reservedDetails ;
1678+ }
1679+
16081680 @ Override
16091681 public boolean start () {
16101682 long pathStateCheckInterval = PathStateCheckInterval .value ();
0 commit comments