mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
server: Added recursive fetch of child domains for listUsageRecords API call (#4717)
When calling the listUasageRecords API records per domain are fetched recursively. This is not the case if you specify a domain id. This PR adds a new parameter to enable fetching records recursively (isRecursive) when passing the domain id.
This commit is contained in:
parent
03c05bc38a
commit
99a9063cf4
@ -85,6 +85,11 @@ public class ListUsageRecordsCmd extends BaseListCmd {
|
|||||||
@Parameter(name = ApiConstants.OLD_FORMAT, type = CommandType.BOOLEAN, description = "Flag to enable description rendered in old format which uses internal database IDs instead of UUIDs. False by default.")
|
@Parameter(name = ApiConstants.OLD_FORMAT, type = CommandType.BOOLEAN, description = "Flag to enable description rendered in old format which uses internal database IDs instead of UUIDs. False by default.")
|
||||||
private Boolean oldFormat;
|
private Boolean oldFormat;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_RECURSIVE, type = CommandType.BOOLEAN,
|
||||||
|
description = "Specify if usage records should be fetched recursively per domain. If an account id is passed, records will be limited to that account.",
|
||||||
|
since = "4.15")
|
||||||
|
private Boolean recursive = false;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -153,6 +158,10 @@ public class ListUsageRecordsCmd extends BaseListCmd {
|
|||||||
return oldFormat != null && oldFormat;
|
return oldFormat != null && oldFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean isRecursive() {
|
||||||
|
return recursive;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import java.util.TimeZone;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import com.cloud.domain.Domain;
|
||||||
import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd;
|
import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd;
|
import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd;
|
||||||
import org.apache.cloudstack.api.command.admin.usage.RemoveRawUsageRecordsCmd;
|
import org.apache.cloudstack.api.command.admin.usage.RemoveRawUsageRecordsCmd;
|
||||||
@ -200,22 +201,41 @@ public class UsageServiceImpl extends ManagerBase implements UsageService, Manag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isAdmin = false;
|
boolean ignoreAccountId = false;
|
||||||
boolean isDomainAdmin = false;
|
boolean isDomainAdmin = _accountService.isDomainAdmin(caller.getId());
|
||||||
|
boolean isNormalUser = _accountService.isNormalUser(caller.getId());
|
||||||
|
|
||||||
//If accountId couldn't be found using accountName and domainId, get it from userContext
|
//If accountId couldn't be found using accountName and domainId, get it from userContext
|
||||||
if (accountId == null) {
|
if (accountId == null) {
|
||||||
accountId = caller.getId();
|
accountId = caller.getId();
|
||||||
//List records for all the accounts if the caller account is of type admin.
|
//List records for all the accounts if the caller account is of type admin.
|
||||||
//If account_id or account_name is explicitly mentioned, list records for the specified account only even if the caller is of type admin
|
//If account_id or account_name is explicitly mentioned, list records for the specified account only even if the caller is of type admin
|
||||||
if (_accountService.isRootAdmin(caller.getId())) {
|
ignoreAccountId = _accountService.isRootAdmin(caller.getId());
|
||||||
isAdmin = true;
|
|
||||||
} else if (_accountService.isDomainAdmin(caller.getId())) {
|
|
||||||
isDomainAdmin = true;
|
|
||||||
}
|
|
||||||
s_logger.debug("Account details not available. Using userContext accountId: " + accountId);
|
s_logger.debug("Account details not available. Using userContext accountId: " + accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if a domain admin is allowed to access the requested domain id
|
||||||
|
if (isDomainAdmin) {
|
||||||
|
if (domainId != null) {
|
||||||
|
Account callerAccount = _accountService.getAccount(caller.getId());
|
||||||
|
Domain domain = _domainDao.findById(domainId);
|
||||||
|
_accountService.checkAccess(callerAccount, domain);
|
||||||
|
} else {
|
||||||
|
// Domain admins can only access their own domain's usage records.
|
||||||
|
// Set the domain if not specified.
|
||||||
|
domainId = caller.getDomainId();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd.getAccountId() != null) {
|
||||||
|
// Check if a domain admin is allowed to access the requested account info.
|
||||||
|
checkDomainAdminAccountAccess(accountId, domainId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default users do not have access to this API.
|
||||||
|
// Adding checks here in case someone changes the default access.
|
||||||
|
checkUserAccess(cmd, accountId, caller, isNormalUser);
|
||||||
|
|
||||||
Date startDate = cmd.getStartDate();
|
Date startDate = cmd.getStartDate();
|
||||||
Date endDate = cmd.getEndDate();
|
Date endDate = cmd.getEndDate();
|
||||||
if (startDate.after(endDate)) {
|
if (startDate.after(endDate)) {
|
||||||
@ -234,23 +254,28 @@ public class UsageServiceImpl extends ManagerBase implements UsageService, Manag
|
|||||||
|
|
||||||
SearchCriteria<UsageVO> sc = _usageDao.createSearchCriteria();
|
SearchCriteria<UsageVO> sc = _usageDao.createSearchCriteria();
|
||||||
|
|
||||||
if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !isAdmin && !isDomainAdmin) {
|
if (accountId != -1 && accountId != Account.ACCOUNT_ID_SYSTEM && !ignoreAccountId) {
|
||||||
|
// account exists and either domain on user role
|
||||||
|
// If not recursive and the account belongs to the user/domain admin, or the account was passed in, filter
|
||||||
|
if ((accountId == caller.getId() && !cmd.isRecursive()) || cmd.getAccountId() != null){
|
||||||
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDomainAdmin) {
|
|
||||||
SearchCriteria<DomainVO> sdc = _domainDao.createSearchCriteria();
|
|
||||||
sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(caller.getDomainId()).getPath() + "%");
|
|
||||||
List<DomainVO> domains = _domainDao.search(sdc, null);
|
|
||||||
List<Long> domainIds = new ArrayList<Long>();
|
|
||||||
for (DomainVO domain : domains)
|
|
||||||
domainIds.add(domain.getId());
|
|
||||||
sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domainId != null) {
|
if (domainId != null) {
|
||||||
|
if (cmd.isRecursive()) {
|
||||||
|
SearchCriteria<DomainVO> sdc = _domainDao.createSearchCriteria();
|
||||||
|
sdc.addOr("path", SearchCriteria.Op.LIKE, _domainDao.findById(domainId).getPath() + "%");
|
||||||
|
List<DomainVO> domains = _domainDao.search(sdc, null);
|
||||||
|
List<Long> domainIds = new ArrayList<Long>();
|
||||||
|
for (DomainVO domain : domains) {
|
||||||
|
domainIds.add(domain.getId());
|
||||||
|
}
|
||||||
|
sc.addAnd("domainId", SearchCriteria.Op.IN, domainIds.toArray());
|
||||||
|
} else {
|
||||||
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
|
sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (usageType != null) {
|
if (usageType != null) {
|
||||||
sc.addAnd("usageType", SearchCriteria.Op.EQ, usageType);
|
sc.addAnd("usageType", SearchCriteria.Op.EQ, usageType);
|
||||||
@ -372,6 +397,46 @@ public class UsageServiceImpl extends ManagerBase implements UsageService, Manag
|
|||||||
return new Pair<List<? extends Usage>, Integer>(usageRecords.first(), usageRecords.second());
|
return new Pair<List<? extends Usage>, Integer>(usageRecords.first(), usageRecords.second());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkUserAccess(ListUsageRecordsCmd cmd, Long accountId, Account caller, boolean isNormalUser) {
|
||||||
|
if (isNormalUser) {
|
||||||
|
// A user can only access their own account records
|
||||||
|
if (caller.getId() != accountId) {
|
||||||
|
throw new PermissionDeniedException("Users are only allowed to list usage records for their own account.");
|
||||||
|
}
|
||||||
|
// Users cannot get recursive records
|
||||||
|
if (cmd.isRecursive()) {
|
||||||
|
throw new PermissionDeniedException("Users are not allowed to list usage records recursively.");
|
||||||
|
}
|
||||||
|
// Users cannot get domain records
|
||||||
|
if (cmd.getDomainId() != null) {
|
||||||
|
throw new PermissionDeniedException("Users are not allowed to list usage records for a domain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkDomainAdminAccountAccess(Long accountId, Long domainId) {
|
||||||
|
Account account = _accountService.getAccount(accountId);
|
||||||
|
boolean matchFound = false;
|
||||||
|
|
||||||
|
if (account.getDomainId() == domainId) {
|
||||||
|
matchFound = true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Check if the account is in a child domain of this domain admin.
|
||||||
|
List<DomainVO> childDomains = _domainDao.findAllChildren(_domainDao.findById(domainId).getPath(), domainId);
|
||||||
|
|
||||||
|
for (DomainVO domainVO : childDomains) {
|
||||||
|
if (account.getDomainId() == domainVO.getId()) {
|
||||||
|
matchFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!matchFound) {
|
||||||
|
throw new PermissionDeniedException("Domain admins may only retrieve usage records for accounts in their own domain and child domains.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimeZone getUsageTimezone() {
|
public TimeZone getUsageTimezone() {
|
||||||
return _usageTimezone;
|
return _usageTimezone;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user