This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new b7a2b0419cc server: Global setting to allow/disallow users to force
stop a vm (#9569)
b7a2b0419cc is described below
commit b7a2b0419ccee96fb80cc43dac9a711927b7f39d
Author: Abhisar Sinha <[email protected]>
AuthorDate: Thu Sep 5 09:46:45 2024 +0530
server: Global setting to allow/disallow users to force stop a vm (#9569)
Global setting to allow/disallow users to force stop a vm
Fixes #6629
Co-authored-by: Suresh Kumar Anaparti <[email protected]>
Co-authored-by: Rohit Yadav <[email protected]>
Co-authored-by: Bernardo De Marco Gonçalves <[email protected]>
---
.../main/java/org/apache/cloudstack/api/ApiConstants.java | 1 +
.../api/command/user/config/ListCapabilitiesCmd.java | 1 +
.../cloudstack/api/response/CapabilitiesResponse.java | 8 ++++++++
.../main/java/com/cloud/server/ManagementServerImpl.java | 2 ++
server/src/main/java/com/cloud/vm/UserVmManager.java | 3 +++
server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 13 ++++++++++++-
ui/src/config/section/compute.js | 5 ++++-
7 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index 2f0e4f16797..96034e0ba8b 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -30,6 +30,7 @@ public class ApiConstants {
public static final String ALGORITHM = "algorithm";
public static final String ALIAS = "alias";
public static final String ALLOCATED_ONLY = "allocatedonly";
+ public static final String ALLOW_USER_FORCE_STOP_VM =
"allowuserforcestopvm";
public static final String ANNOTATION = "annotation";
public static final String API_KEY = "apikey";
public static final String ARCHIVED = "archived";
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
index cf25dfaf5b5..a807d2ad837 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
@@ -55,6 +55,7 @@ public class ListCapabilitiesCmd extends BaseCmd {
response.setAllowUserExpungeRecoverVM((Boolean)capabilities.get("allowUserExpungeRecoverVM"));
response.setAllowUserExpungeRecoverVolume((Boolean)capabilities.get("allowUserExpungeRecoverVolume"));
response.setAllowUserViewAllDomainAccounts((Boolean)capabilities.get("allowUserViewAllDomainAccounts"));
+
response.setAllowUserForceStopVM((Boolean)capabilities.get(ApiConstants.ALLOW_USER_FORCE_STOP_VM));
response.setKubernetesServiceEnabled((Boolean)capabilities.get("kubernetesServiceEnabled"));
response.setKubernetesClusterExperimentalFeaturesEnabled((Boolean)capabilities.get("kubernetesClusterExperimentalFeaturesEnabled"));
response.setCustomHypervisorDisplayName((String)
capabilities.get("customHypervisorDisplayName"));
diff --git
a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
index e4224c85e97..162386ee042 100644
---
a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
+++
b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java
@@ -92,6 +92,10 @@ public class CapabilitiesResponse extends BaseResponse {
@Param(description = "true if users can see all accounts within the same
domain, false otherwise")
private boolean allowUserViewAllDomainAccounts;
+ @SerializedName(ApiConstants.ALLOW_USER_FORCE_STOP_VM)
+ @Param(description = "true if users are allowed to force stop a vm, false
otherwise", since = "4.20.0")
+ private boolean allowUserForceStopVM;
+
@SerializedName("kubernetesserviceenabled")
@Param(description = "true if Kubernetes Service plugin is enabled, false
otherwise")
private boolean kubernetesServiceEnabled;
@@ -192,6 +196,10 @@ public class CapabilitiesResponse extends BaseResponse {
this.allowUserViewAllDomainAccounts = allowUserViewAllDomainAccounts;
}
+ public void setAllowUserForceStopVM(boolean allowUserForceStopVM) {
+ this.allowUserForceStopVM = allowUserForceStopVM;
+ }
+
public void setKubernetesServiceEnabled(boolean kubernetesServiceEnabled) {
this.kubernetesServiceEnabled = kubernetesServiceEnabled;
}
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index fb3cf9bf193..fabf82e5182 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -4461,6 +4461,7 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
final boolean allowUserViewDestroyedVM =
(QueryService.AllowUserViewDestroyedVM.valueIn(caller.getId()) |
_accountService.isAdmin(caller.getId()));
final boolean allowUserExpungeRecoverVM =
(UserVmManager.AllowUserExpungeRecoverVm.valueIn(caller.getId()) |
_accountService.isAdmin(caller.getId()));
final boolean allowUserExpungeRecoverVolume =
(VolumeApiServiceImpl.AllowUserExpungeRecoverVolume.valueIn(caller.getId()) |
_accountService.isAdmin(caller.getId()));
+ final boolean allowUserForceStopVM =
(UserVmManager.AllowUserForceStopVm.valueIn(caller.getId()) |
_accountService.isAdmin(caller.getId()));
final boolean allowUserViewAllDomainAccounts =
(QueryService.AllowUserViewAllDomainAccounts.valueIn(caller.getDomainId()));
@@ -4488,6 +4489,7 @@ public class ManagementServerImpl extends ManagerBase
implements ManagementServe
capabilities.put("allowUserExpungeRecoverVM",
allowUserExpungeRecoverVM);
capabilities.put("allowUserExpungeRecoverVolume",
allowUserExpungeRecoverVolume);
capabilities.put("allowUserViewAllDomainAccounts",
allowUserViewAllDomainAccounts);
+ capabilities.put(ApiConstants.ALLOW_USER_FORCE_STOP_VM,
allowUserForceStopVM);
capabilities.put("kubernetesServiceEnabled", kubernetesServiceEnabled);
capabilities.put("kubernetesClusterExperimentalFeaturesEnabled",
kubernetesClusterExperimentalFeaturesEnabled);
capabilities.put("customHypervisorDisplayName",
HypervisorGuru.HypervisorCustomDisplayName.value());
diff --git a/server/src/main/java/com/cloud/vm/UserVmManager.java
b/server/src/main/java/com/cloud/vm/UserVmManager.java
index 0dc7a7bb73f..047bc8ea6d2 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManager.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManager.java
@@ -51,12 +51,15 @@ public interface UserVmManager extends UserVmService {
String EnableDynamicallyScaleVmCK = "enable.dynamic.scale.vm";
String AllowDiskOfferingChangeDuringScaleVmCK =
"allow.diskoffering.change.during.scale.vm";
String AllowUserExpungeRecoverVmCK ="allow.user.expunge.recover.vm";
+ String AllowUserForceStopVmCK = "allow.user.force.stop.vm";
ConfigKey<Boolean> EnableDynamicallyScaleVm = new
ConfigKey<Boolean>("Advanced", Boolean.class, EnableDynamicallyScaleVmCK,
"false",
"Enables/Disables dynamically scaling a vm", true,
ConfigKey.Scope.Zone);
ConfigKey<Boolean> AllowDiskOfferingChangeDuringScaleVm = new
ConfigKey<Boolean>("Advanced", Boolean.class,
AllowDiskOfferingChangeDuringScaleVmCK, "false",
"Determines whether to allow or disallow disk offering change for
root volume during scaling of a stopped or running vm", true,
ConfigKey.Scope.Zone);
ConfigKey<Boolean> AllowUserExpungeRecoverVm = new
ConfigKey<Boolean>("Advanced", Boolean.class, AllowUserExpungeRecoverVmCK,
"false",
"Determines whether users can expunge or recover their vm", true,
ConfigKey.Scope.Account);
+ ConfigKey<Boolean> AllowUserForceStopVm = new
ConfigKey<Boolean>("Advanced", Boolean.class, AllowUserForceStopVmCK, "true",
+ "Determines whether users are allowed to force stop a vm", true,
ConfigKey.Scope.Account);
ConfigKey<Boolean> DisplayVMOVFProperties = new
ConfigKey<Boolean>("Advanced", Boolean.class, "vm.display.ovf.properties",
"false",
"Set display of VMs OVF properties as part of VM details", true);
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index 22ef809e5da..0dc0e84cbd4 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -5348,6 +5348,13 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
public void finalizeExpunge(VirtualMachine vm) {
}
+ private void checkForceStopVmPermission(Account callingAccount) {
+ if (!AllowUserForceStopVm.valueIn(callingAccount.getId())) {
+ logger.error("Parameter [{}] can only be passed by Admin accounts
or when the allow.user.force.stop.vm config is true for the account.",
ApiConstants.FORCED);
+ throw new PermissionDeniedException("Account does not have the
permission to force stop the vm.");
+ }
+ }
+
@Override
@ActionEvent(eventType = EventTypes.EVENT_VM_STOP, eventDescription =
"stopping Vm", async = true)
public UserVm stopVirtualMachine(long vmId, boolean forced) throws
ConcurrentOperationException {
@@ -5365,6 +5372,10 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
throw new InvalidParameterValueException("unable to find a virtual
machine with id " + vmId);
}
+ if (forced) {
+ checkForceStopVmPermission(caller);
+ }
+
// check if vm belongs to AutoScale vm group in Disabled state
autoScaleManager.checkIfVmActionAllowed(vmId);
@@ -8467,7 +8478,7 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
return new ConfigKey<?>[] {EnableDynamicallyScaleVm,
AllowDiskOfferingChangeDuringScaleVm, AllowUserExpungeRecoverVm,
VmIpFetchWaitInterval, VmIpFetchTrialMax,
VmIpFetchThreadPoolMax, VmIpFetchTaskWorkers,
AllowDeployVmIfGivenHostFails, EnableAdditionalVmConfig, DisplayVMOVFProperties,
KvmAdditionalConfigAllowList,
XenServerAdditionalConfigAllowList, VmwareAdditionalConfigAllowList,
DestroyRootVolumeOnVmDestruction,
- EnforceStrictResourceLimitHostTagCheck, StrictHostTags};
+ EnforceStrictResourceLimitHostTagCheck, StrictHostTags,
AllowUserForceStopVm};
}
@Override
diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js
index 4c5a61e3bdc..7c7480a7b75 100644
--- a/ui/src/config/section/compute.js
+++ b/ui/src/config/section/compute.js
@@ -133,7 +133,10 @@ export default {
dataView: true,
groupAction: true,
groupMap: (selection, values) => { return selection.map(x => {
return { id: x, forced: values.forced } }) },
- args: ['forced'],
+ args: (record, store, group) => {
+ return (['Admin'].includes(store.userInfo.roletype) ||
store.features.allowuserforcestopvm)
+ ? ['forced'] : []
+ },
show: (record) => { return ['Running'].includes(record.state) }
},
{