diff --git a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index e6696e17ff0..24486a3c79b 100644 --- a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -18,11 +18,10 @@ package org.apache.cloudstack.api.command.user.config; import java.util.Map; -import org.apache.log4j.Logger; - import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.response.CapabilitiesResponse; +import org.apache.log4j.Logger; import com.cloud.user.Account; @@ -57,6 +56,8 @@ public class ListCapabilitiesCmd extends BaseCmd { response.setDiskOffMaxSize((Long)capabilities.get("customDiskOffMaxSize")); response.setRegionSecondaryEnabled((Boolean)capabilities.get("regionSecondaryEnabled")); response.setKVMSnapshotEnabled((Boolean)capabilities.get("KVMSnapshotEnabled")); + response.setAllowUserViewDestroyedVM((Boolean)capabilities.get("allowUserViewDestroyedVM")); + response.setAllowUserExpungeRecoverVM((Boolean)capabilities.get("allowUserExpungeRecoverVM")); if (capabilities.containsKey("apiLimitInterval")) { response.setApiLimitInterval((Integer)capabilities.get("apiLimitInterval")); } diff --git a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java index f7fdb95fb6e..623a0a231f7 100644 --- a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java +++ b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java @@ -16,12 +16,11 @@ // under the License. package org.apache.cloudstack.api.response; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") public class CapabilitiesResponse extends BaseResponse { @@ -73,6 +72,14 @@ public class CapabilitiesResponse extends BaseResponse { @Param(description = "Max allowed number of api requests within the specified interval") private Integer apiLimitMax; + @SerializedName("allowuserviewdestroyedvm") + @Param(description = "true if the user is allowed to view destroyed virtualmachines, false otherwise", since = "4.6.0") + private boolean allowUserViewDestroyedVM; + + @SerializedName("allowuserexpungerecovervm") + @Param(description = "true if the user can recover and expunge virtualmachines, false otherwise", since = "4.6.0") + private boolean allowUserExpungeRecoverVM; + public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) { this.securityGroupsEnabled = securityGroupsEnabled; } @@ -121,4 +128,11 @@ public class CapabilitiesResponse extends BaseResponse { this.apiLimitMax = apiLimitMax; } -} + public void setAllowUserViewDestroyedVM(boolean allowUserViewDestroyedVM) { + this.allowUserViewDestroyedVM = allowUserViewDestroyedVM; + } + + public void setAllowUserExpungeRecoverVM(boolean allowUserExpungeRecoverVM) { + this.allowUserExpungeRecoverVM = allowUserExpungeRecoverVM; + } +} \ No newline at end of file diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index bd2afa326db..4162bf2f146 100644 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -525,6 +525,7 @@ import com.cloud.alert.AlertManager; import com.cloud.alert.AlertVO; import com.cloud.alert.dao.AlertDao; import com.cloud.api.ApiDBUtils; +import com.cloud.api.query.QueryManagerImpl; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; @@ -3378,6 +3379,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe final Integer apiLimitInterval = Integer.valueOf(_configDao.getValue(Config.ApiLimitInterval.key())); final Integer apiLimitMax = Integer.valueOf(_configDao.getValue(Config.ApiLimitMax.key())); + final boolean allowUserViewDestroyedVM = (QueryManagerImpl.AllowUserViewDestroyedVM.valueIn(caller.getId()) | _accountService.isAdmin(caller.getId())); + final boolean allowUserExpungeRecoverVM = (UserVmManager.AllowUserExpungeRecoverVm.valueIn(caller.getId()) | _accountService.isAdmin(caller.getId())); + // check if region-wide secondary storage is used boolean regionSecondaryEnabled = false; final List imgStores = _imgStoreDao.findRegionImageStores(); @@ -3395,6 +3399,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe capabilities.put("customDiskOffMaxSize", diskOffMaxSize); capabilities.put("regionSecondaryEnabled", regionSecondaryEnabled); capabilities.put("KVMSnapshotEnabled", KVMSnapshotEnabled); + capabilities.put("allowUserViewDestroyedVM", allowUserViewDestroyedVM); + capabilities.put("allowUserExpungeRecoverVM", allowUserExpungeRecoverVM); if (apiLimitEnabled) { capabilities.put("apiLimitInterval", apiLimitInterval); capabilities.put("apiLimitMax", apiLimitMax); diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js index 146f8d1083d..8137043cbc3 100644 --- a/ui/scripts/cloudStack.js +++ b/ui/scripts/cloudStack.js @@ -143,8 +143,9 @@ if (json.listcapabilitiesresponse.capability.userpublictemplateenabled != null) { g_userPublicTemplateEnabled = json.listcapabilitiesresponse.capability.userpublictemplateenabled.toString(); //convert boolean to string if it's boolean } - g_userProjectsEnabled = json.listcapabilitiesresponse.capability.allowusercreateprojects; + g_allowUserExpungeRecoverVm = json.listcapabilitiesresponse.capability.allowuserexpungerecovervm; + g_userProjectsEnabled = json.listcapabilitiesresponse.capability.allowusercreateprojects; g_cloudstackversion = json.listcapabilitiesresponse.capability.cloudstackversion; @@ -274,9 +275,9 @@ if (json.listcapabilitiesresponse.capability.userpublictemplateenabled != null) { g_userPublicTemplateEnabled = json.listcapabilitiesresponse.capability.userpublictemplateenabled.toString(); //convert boolean to string if it's boolean } + g_allowUserExpungeRecoverVm = json.listcapabilitiesresponse.capability.allowuserexpungerecovervm; g_userProjectsEnabled = json.listcapabilitiesresponse.capability.allowusercreateprojects; - g_cloudstackversion = json.listcapabilitiesresponse.capability.cloudstackversion; if (json.listcapabilitiesresponse.capability.apilimitinterval != null && json.listcapabilitiesresponse.capability.apilimitmax != null) { diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 3fdd7701fbf..09e284a361b 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -618,11 +618,9 @@ createForm: { title: 'label.action.destroy.instance', desc: 'label.action.destroy.instance', - isWarning: true, + isWarning: true, preFilter: function(args) { - if (isAdmin() || isDomainAdmin()) { - args.$form.find('.form-item[rel=expunge]').css('display', 'inline-block'); - } else { + if (! g_allowUserExpungeRecoverVm) { args.$form.find('.form-item[rel=expunge]').hide(); } }, @@ -2425,11 +2423,13 @@ var allowedActions = []; if (jsonObj.state == 'Destroyed') { - if (isAdmin() || isDomainAdmin()) { + if (g_allowUserExpungeRecoverVm) { allowedActions.push("recover"); } - if (isAdmin() || isDomainAdmin()) + + if (g_allowUserExpungeRecoverVm) { allowedActions.push("expunge"); + } } else if (jsonObj.state == 'Running') { allowedActions.push("stop"); allowedActions.push("restart"); @@ -2498,8 +2498,9 @@ } else if (jsonObj.state == 'Error') { allowedActions.push("destroy"); } else if (jsonObj.state == 'Expunging') { - if (isAdmin() || isDomainAdmin()) + if (g_allowUserExpungeRecoverVm) { allowedActions.push("expunge"); + } } return allowedActions; } diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index daf3eb56818..7b4b26a0ca2 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -30,6 +30,7 @@ var g_supportELB = null; var g_kvmsnapshotenabled = null; var g_regionsecondaryenabled = null; var g_userPublicTemplateEnabled = "true"; +var g_allowUserExpungeRecoverVm = "false"; var g_cloudstackversion = null; var g_queryAsyncJobResultInterval = 3000; var g_idpList = null; @@ -2332,4 +2333,3 @@ $.validator.addMethod("ipv4cidr", function(value, element) { return true; }, "The specified IPv4 CIDR is invalid."); -