Skip to content

Commit dd7dfc3

Browse files
author
Boris Schrijver
committed
CLOUDSTACK-8580 Users are now able to view, expunge and recover their vm's themselves. Two configuration options are added to allow this behaviour on a global or per account scale. Configuration options default to false.
1 parent 373b2c7 commit dd7dfc3

6 files changed

Lines changed: 39 additions & 13 deletions

File tree

api/src/org/apache/cloudstack/api/command/user/vm/DestroyVMCmd.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
import com.cloud.uservm.UserVm;
4141
import com.cloud.vm.VirtualMachine;
4242

43-
@APICommand(name = "destroyVirtualMachine", description = "Destroys a virtual machine. Once destroyed, only the administrator can recover it.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
43+
@APICommand(name = "destroyVirtualMachine", description = "Destroys a virtual machine.", responseObject = UserVmResponse.class, responseView = ResponseView.Restricted, entityType = {VirtualMachine.class},
4444
requestHasSensitiveInfo = false,
4545
responseHasSensitiveInfo = true)
4646
public class DestroyVMCmd extends BaseAsyncCmd {
@@ -59,7 +59,7 @@ public class DestroyVMCmd extends BaseAsyncCmd {
5959

6060
@Parameter(name = ApiConstants.EXPUNGE,
6161
type = CommandType.BOOLEAN,
62-
description = "If true is passed, the vm is expunged immediately. False by default. Parameter can be passed to the call by ROOT/Domain admin only",
62+
description = "If true is passed, the vm is expunged immediately. False by default.",
6363
since = "4.2.1")
6464
private Boolean expunge;
6565

api/src/org/apache/cloudstack/query/QueryService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import org.apache.cloudstack.api.response.UserVmResponse;
7272
import org.apache.cloudstack.api.response.VolumeResponse;
7373
import org.apache.cloudstack.api.response.ZoneResponse;
74+
import org.apache.cloudstack.framework.config.ConfigKey;
7475

7576
import com.cloud.exception.PermissionDeniedException;
7677

@@ -80,6 +81,10 @@
8081
*/
8182
public interface QueryService {
8283

84+
// Config keys
85+
static final ConfigKey<Boolean> AllowUserViewDestroyedVM = new ConfigKey<Boolean>("Advanced", Boolean.class, "allow.user.view.destroyed.vm", "false",
86+
"Determines whether users can view their destroyed or expunging vm ", true, ConfigKey.Scope.Account);
87+
8388
ListResponse<UserResponse> searchForUsers(ListUsersCmd cmd) throws PermissionDeniedException;
8489

8590
ListResponse<EventResponse> searchForEvents(ListEventsCmd cmd);

client/tomcatconf/commands.properties.in

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ scaleVirtualMachine=15
8282
assignVirtualMachine=7
8383
migrateVirtualMachine=1
8484
migrateVirtualMachineWithVolume=1
85-
recoverVirtualMachine=7
86-
expungeVirtualMachine=7
85+
recoverVirtualMachine=15
86+
expungeVirtualMachine=15
8787
getVirtualMachineUserData=15
8888

8989
#### snapshot commands

server/src/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
104104
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
105105
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState;
106+
import org.apache.cloudstack.framework.config.ConfigKey;
107+
import org.apache.cloudstack.framework.config.Configurable;
106108
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
107109
import org.apache.cloudstack.query.QueryService;
108110
import org.apache.log4j.Logger;
@@ -223,7 +225,7 @@
223225

224226
@Component
225227
@Local(value = {QueryService.class})
226-
public class QueryManagerImpl extends ManagerBase implements QueryService {
228+
public class QueryManagerImpl extends ManagerBase implements QueryService, Configurable {
227229

228230
public static final Logger s_logger = Logger.getLogger(QueryManagerImpl.class);
229231

@@ -979,8 +981,8 @@ private Pair<List<UserVmJoinVO>, Integer> searchForUserVMsInternal(ListVMsCmd cm
979981
sc.setParameters("hypervisorType", hypervisor);
980982
}
981983

982-
// Don't show Destroyed and Expunging vms to the end user
983-
if (!isAdmin) {
984+
// Don't show Destroyed and Expunging vms to the end user if the AllowUserViewDestroyedVM flag is not set.
985+
if (!isAdmin && !AllowUserViewDestroyedVM.valueIn(caller.getAccountId())) {
984986
sc.setParameters("stateNIN", "Destroyed", "Expunging");
985987
}
986988

@@ -3685,4 +3687,13 @@ protected ResourceDetailResponse createResourceDetailsResponse(ResourceDetail re
36853687
return resourceDetailResponse;
36863688
}
36873689

3690+
@Override
3691+
public String getConfigComponentName() {
3692+
return QueryService.class.getSimpleName();
3693+
}
3694+
3695+
@Override
3696+
public ConfigKey<?>[] getConfigKeys() {
3697+
return new ConfigKey<?>[] {AllowUserViewDestroyedVM};
3698+
}
36883699
}

server/src/com/cloud/vm/UserVmManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@
4242
*/
4343
public interface UserVmManager extends UserVmService {
4444
static final String EnableDynamicallyScaleVmCK = "enable.dynamic.scale.vm";
45+
static final String AllowUserExpungeRecoverVmCK ="allow.user.expunge.recover.vm";
4546
static final ConfigKey<Boolean> EnableDynamicallyScaleVm = new ConfigKey<Boolean>("Advanced", Boolean.class, EnableDynamicallyScaleVmCK, "false",
4647
"Enables/Disables dynamically scaling a vm", true, ConfigKey.Scope.Zone);
48+
static final ConfigKey<Boolean> AllowUserExpungeRecoverVm = new ConfigKey<Boolean>("Advanced", Boolean.class, AllowUserExpungeRecoverVmCK, "false",
49+
"Determines whether users can expunge or recover their vm", true, ConfigKey.Scope.Account);
4750

4851
static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
4952

server/src/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,7 @@ public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationE
17051705

17061706
final Long vmId = cmd.getId();
17071707
Account caller = CallContext.current().getCallingAccount();
1708+
final Long userId = caller.getAccountId();
17081709

17091710
// Verify input parameters
17101711
final UserVmVO vm = _vmDao.findById(vmId);
@@ -1713,8 +1714,10 @@ public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationE
17131714
throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmId);
17141715
}
17151716

1716-
// check permissions
1717-
_accountMgr.checkAccess(caller, null, true, vm);
1717+
// When trying to expunge, permission is denied when the caller is not an admin and the AllowUserExpungeRecoverVm is false for the caller.
1718+
if (!_accountMgr.isAdmin(userId) && !AllowUserExpungeRecoverVm.valueIn(userId)) {
1719+
throw new PermissionDeniedException("Recovering a vm can only be done by an Admin. Or when the allow.user.expunge.recover.vm key is set.");
1720+
}
17181721

17191722
if (vm.getRemoved() != null) {
17201723
if (s_logger.isDebugEnabled()) {
@@ -2404,8 +2407,9 @@ public UserVm destroyVm(DestroyVMCmd cmd) throws ResourceUnavailableException, C
24042407
long vmId = cmd.getId();
24052408
boolean expunge = cmd.getExpunge();
24062409

2407-
if (!_accountMgr.isAdmin(ctx.getCallingAccount().getId()) && expunge) {
2408-
throw new PermissionDeniedException("Parameter " + ApiConstants.EXPUNGE + " can be passed by Admin only");
2410+
// When trying to expunge, permission is denied when the caller is not an admin and the AllowUserExpungeRecoverVm is false for the caller.
2411+
if (expunge && !_accountMgr.isAdmin(ctx.getCallingAccount().getId()) && !AllowUserExpungeRecoverVm.valueIn(cmd.getEntityOwnerId())) {
2412+
throw new PermissionDeniedException("Parameter " + ApiConstants.EXPUNGE + " can be passed by Admin only. Or when the allow.user.expunge.recover.vm key is set.");
24092413
}
24102414

24112415
UserVm destroyedVm = destroyVm(vmId);
@@ -4072,7 +4076,10 @@ public UserVm expungeVm(long vmId) throws ResourceUnavailableException, Concurre
40724076
throw ex;
40734077
}
40744078

4075-
_accountMgr.checkAccess(caller, null, true, vm);
4079+
// When trying to expunge, permission is denied when the caller is not an admin and the AllowUserExpungeRecoverVm is false for the caller.
4080+
if (!_accountMgr.isAdmin(userId) && !AllowUserExpungeRecoverVm.valueIn(userId)) {
4081+
throw new PermissionDeniedException("Expunging a vm can only be done by an Admin. Or when the allow.user.expunge.recover.vm key is set.");
4082+
}
40764083

40774084
boolean status;
40784085

@@ -5292,7 +5299,7 @@ public String getConfigComponentName() {
52925299

52935300
@Override
52945301
public ConfigKey<?>[] getConfigKeys() {
5295-
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax};
5302+
return new ConfigKey<?>[] {EnableDynamicallyScaleVm, AllowUserExpungeRecoverVm, VmIpFetchWaitInterval, VmIpFetchTrialMax, VmIpFetchThreadPoolMax};
52965303
}
52975304

52985305
@Override

0 commit comments

Comments
 (0)