CLOUDSTACK-7983: Create Disk/Service Offering for Domain Admin

This commit is contained in:
Wei Zhou 2014-12-01 13:03:37 +01:00
parent 45423c737e
commit af2f21894c
14 changed files with 318 additions and 96 deletions

View File

@ -25,6 +25,8 @@ import org.apache.cloudstack.api.command.admin.user.RegisterCmd;
import com.cloud.domain.Domain; import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
public interface AccountService { public interface AccountService {
@ -111,6 +113,10 @@ public interface AccountService {
void checkAccess(Account account, AccessType accessType, boolean sameOwner, ControlledEntity... entities) throws PermissionDeniedException; void checkAccess(Account account, AccessType accessType, boolean sameOwner, ControlledEntity... entities) throws PermissionDeniedException;
void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException;
void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException;
void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName,
ControlledEntity... entities) throws PermissionDeniedException; ControlledEntity... entities) throws PermissionDeniedException;

View File

@ -20,15 +20,14 @@ import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.BaseListDomainResourcesCmd;
import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
@APICommand(name = "listDiskOfferings", description = "Lists all available disk offerings.", responseObject = DiskOfferingResponse.class, @APICommand(name = "listDiskOfferings", description = "Lists all available disk offerings.", responseObject = DiskOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListDiskOfferingsCmd extends BaseListCmd { public class ListDiskOfferingsCmd extends BaseListDomainResourcesCmd {
public static final Logger s_logger = Logger.getLogger(ListDiskOfferingsCmd.class.getName()); public static final Logger s_logger = Logger.getLogger(ListDiskOfferingsCmd.class.getName());
private static final String s_name = "listdiskofferingsresponse"; private static final String s_name = "listdiskofferingsresponse";
@ -37,9 +36,6 @@ public class ListDiskOfferingsCmd extends BaseListCmd {
//////////////// API parameters ///////////////////// //////////////// API parameters /////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "the ID of the domain of the disk offering.")
private Long domainId;
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "ID of the disk offering") @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "ID of the disk offering")
private Long id; private Long id;
@ -50,10 +46,6 @@ public class ListDiskOfferingsCmd extends BaseListCmd {
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
public Long getDomainId() {
return domainId;
}
public Long getId() { public Long getId() {
return id; return id;
} }

View File

@ -20,16 +20,15 @@ import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.BaseListDomainResourcesCmd;
import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.UserVmResponse;
@APICommand(name = "listServiceOfferings", description = "Lists all available service offerings.", responseObject = ServiceOfferingResponse.class, @APICommand(name = "listServiceOfferings", description = "Lists all available service offerings.", responseObject = ServiceOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ListServiceOfferingsCmd extends BaseListCmd { public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd {
public static final Logger s_logger = Logger.getLogger(ListServiceOfferingsCmd.class.getName()); public static final Logger s_logger = Logger.getLogger(ListServiceOfferingsCmd.class.getName());
private static final String s_name = "listserviceofferingsresponse"; private static final String s_name = "listserviceofferingsresponse";
@ -50,12 +49,6 @@ public class ListServiceOfferingsCmd extends BaseListCmd {
description = "the ID of the virtual machine. Pass this in if you want to see the available service offering that a virtual machine can be changed to.") description = "the ID of the virtual machine. Pass this in if you want to see the available service offering that a virtual machine can be changed to.")
private Long virtualMachineId; private Long virtualMachineId;
@Parameter(name = ApiConstants.DOMAIN_ID,
type = CommandType.UUID,
entityType = DomainResponse.class,
description = "the ID of the domain associated with the service offering")
private Long domainId;
@Parameter(name=ApiConstants.IS_SYSTEM_OFFERING, type=CommandType.BOOLEAN, description="is this a system vm offering") @Parameter(name=ApiConstants.IS_SYSTEM_OFFERING, type=CommandType.BOOLEAN, description="is this a system vm offering")
private Boolean isSystem; private Boolean isSystem;
@ -80,10 +73,6 @@ public class ListServiceOfferingsCmd extends BaseListCmd {
return virtualMachineId; return virtualMachineId;
} }
public Long getDomainId() {
return domainId;
}
public Boolean getIsSystem() { public Boolean getIsSystem() {
return isSystem == null ? false : isSystem; return isSystem == null ? false : isSystem;
} }

View File

@ -131,15 +131,15 @@ updateGuestOsMapping=1
removeGuestOsMapping=1 removeGuestOsMapping=1
#### service offering commands #### service offering commands
createServiceOffering=1 createServiceOffering=7
deleteServiceOffering=1 deleteServiceOffering=7
updateServiceOffering=1 updateServiceOffering=7
listServiceOfferings=15 listServiceOfferings=15
#### disk offering commands #### disk offering commands
createDiskOffering=1 createDiskOffering=7
updateDiskOffering=1 updateDiskOffering=7
deleteDiskOffering=1 deleteDiskOffering=7
listDiskOfferings=15 listDiskOfferings=15
#### vlan commands #### vlan commands

View File

@ -42,6 +42,8 @@ import com.cloud.domain.Domain;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
@ -401,4 +403,14 @@ public class MockAccountManager extends ManagerBase implements AccountManager {
// TODO Auto-generated method stub // TODO Auto-generated method stub
return null; return null;
} }
@Override
public void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException {
// TODO Auto-generated method stub
}
@Override
public void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException {
// TODO Auto-generated method stub
}
} }

View File

@ -170,7 +170,7 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
@Override @Override
public boolean checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException { public boolean checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException {
if (account == null || dof.getDomainId() == null) {//public offering if (account == null || dof == null || dof.getDomainId() == null) {//public offering
return true; return true;
} else { } else {
//admin has all permissions //admin has all permissions

View File

@ -2422,6 +2422,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
Object keyword = cmd.getKeyword(); Object keyword = cmd.getKeyword();
Long domainId = cmd.getDomainId(); Long domainId = cmd.getDomainId();
Boolean isRootAdmin = _accountMgr.isRootAdmin(account.getAccountId()); Boolean isRootAdmin = _accountMgr.isRootAdmin(account.getAccountId());
Boolean isRecursive = cmd.isRecursive();
// Keeping this logic consistent with domain specific zones // Keeping this logic consistent with domain specific zones
// if a domainId is provided, we just return the disk offering // if a domainId is provided, we just return the disk offering
// associated with this domain // associated with this domain
@ -2444,6 +2445,12 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
// and everything above till root // and everything above till root
if ((_accountMgr.isNormalUser(account.getId()) || _accountMgr.isDomainAdmin(account.getId())) if ((_accountMgr.isNormalUser(account.getId()) || _accountMgr.isDomainAdmin(account.getId()))
|| account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { || account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
if (isRecursive) { // domain + all sub-domains
if (account.getType() == Account.ACCOUNT_TYPE_NORMAL)
throw new InvalidParameterValueException("Only ROOT admins and Domain admins can list disk offerings with isrecursive=true");
DomainVO domainRecord = _domainDao.findById(account.getDomainId());
sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domainRecord.getPath() + "%");
} else { // domain + all ancestors
// find all domain Id up to root domain for this account // find all domain Id up to root domain for this account
domainIds = new ArrayList<Long>(); domainIds = new ArrayList<Long>();
DomainVO domainRecord = _domainDao.findById(account.getDomainId()); DomainVO domainRecord = _domainDao.findById(account.getDomainId());
@ -2460,16 +2467,10 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
SearchCriteria<DiskOfferingJoinVO> spc = _diskOfferingJoinDao.createSearchCriteria(); SearchCriteria<DiskOfferingJoinVO> spc = _diskOfferingJoinDao.createSearchCriteria();
spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray());
spc.addOr("domainId", SearchCriteria.Op.NULL); // include public spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as where
// offering as where
sc.addAnd("domainId", SearchCriteria.Op.SC, spc); sc.addAnd("domainId", SearchCriteria.Op.SC, spc);
sc.addAnd("displayOffering", SearchCriteria.Op.EQ, 1); sc.addAnd("systemUse", SearchCriteria.Op.EQ, false); // non-root users should not see system offering at all
sc.addAnd("systemUse", SearchCriteria.Op.EQ, false); // non-root }
// users should
// not see
// system
// offering at
// all
} }
@ -2563,6 +2564,7 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
Boolean isSystem = cmd.getIsSystem(); Boolean isSystem = cmd.getIsSystem();
String vmTypeStr = cmd.getSystemVmType(); String vmTypeStr = cmd.getSystemVmType();
ServiceOfferingVO currentVmOffering = null; ServiceOfferingVO currentVmOffering = null;
Boolean isRecursive = cmd.isRecursive();
SearchCriteria<ServiceOfferingJoinVO> sc = _srvOfferingJoinDao.createSearchCriteria(); SearchCriteria<ServiceOfferingJoinVO> sc = _srvOfferingJoinDao.createSearchCriteria();
if (!_accountMgr.isRootAdmin(caller.getId()) && isSystem) { if (!_accountMgr.isRootAdmin(caller.getId()) && isSystem) {
@ -2611,6 +2613,12 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
if (isSystem) { if (isSystem) {
throw new InvalidParameterValueException("Only root admins can access system's offering"); throw new InvalidParameterValueException("Only root admins can access system's offering");
} }
if (isRecursive) { // domain + all sub-domains
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL)
throw new InvalidParameterValueException("Only ROOT admins and Domain admins can list service offerings with isrecursive=true");
DomainVO domainRecord = _domainDao.findById(caller.getDomainId());
sc.addAnd("domainPath", SearchCriteria.Op.LIKE, domainRecord.getPath() + "%");
} else { // domain + all ancestors
// find all domain Id up to root domain for this account // find all domain Id up to root domain for this account
List<Long> domainIds = new ArrayList<Long>(); List<Long> domainIds = new ArrayList<Long>();
DomainVO domainRecord; DomainVO domainRecord;
@ -2633,13 +2641,12 @@ public class QueryManagerImpl extends ManagerBase implements QueryService {
domainRecord = _domainDao.findById(domainRecord.getParent()); domainRecord = _domainDao.findById(domainRecord.getParent());
domainIds.add(domainRecord.getId()); domainIds.add(domainRecord.getId());
} }
SearchCriteria<ServiceOfferingJoinVO> spc = _srvOfferingJoinDao.createSearchCriteria(); SearchCriteria<ServiceOfferingJoinVO> spc = _srvOfferingJoinDao.createSearchCriteria();
spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray()); spc.addOr("domainId", SearchCriteria.Op.IN, domainIds.toArray());
spc.addOr("domainId", SearchCriteria.Op.NULL); // include public spc.addOr("domainId", SearchCriteria.Op.NULL); // include public offering as well
// offering as where
sc.addAnd("domainId", SearchCriteria.Op.SC, spc); sc.addAnd("domainId", SearchCriteria.Op.SC, spc);
}
} else { } else {
// for root users // for root users
if (caller.getDomainId() != 1 && isSystem) { // NON ROOT admin if (caller.getDomainId() != 1 && isSystem) { // NON ROOT admin

View File

@ -111,10 +111,10 @@ public class DiskOfferingJoinVO extends BaseViewVO implements InternalIdentity,
private String domainUuid; private String domainUuid;
@Column(name = "domain_name") @Column(name = "domain_name")
private final String domainName = null; private String domainName = null;
@Column(name = "domain_path") @Column(name = "domain_path")
private final String domainPath = null; private String domainPath = null;
@Column(name = "display_offering") @Column(name = "display_offering")
boolean displayOffering; boolean displayOffering;

View File

@ -190,6 +190,7 @@ import com.cloud.user.AccountVO;
import com.cloud.user.ResourceLimitService; import com.cloud.user.ResourceLimitService;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils; import com.cloud.utils.StringUtils;
@ -287,6 +288,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Inject @Inject
VpcManager _vpcMgr; VpcManager _vpcMgr;
@Inject @Inject
UserDao _userDao;
@Inject
PortableIpRangeDao _portableIpRangeDao; PortableIpRangeDao _portableIpRangeDao;
@Inject @Inject
RegionDao _regionDao; RegionDao _regionDao;
@ -2103,9 +2106,30 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
Integer networkRate, String deploymentPlanner, Map<String, String> details, Boolean isCustomizedIops, Long minIops, Long maxIops, Integer networkRate, String deploymentPlanner, Map<String, String> details, Boolean isCustomizedIops, Long minIops, Long maxIops,
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, Integer hypervisorSnapshotReserve) { Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, Integer hypervisorSnapshotReserve) {
// Check if user exists in the system
User user = _userDao.findById(userId);
if (user == null || user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
Account account = _accountDao.findById(user.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (domainId == null) {
throw new InvalidParameterValueException("Unable to create public service offering by id " + userId + " because it is domain-admin");
}
if (tags != null || hostTag != null) {
throw new InvalidParameterValueException("Unable to create service offering with storage tags or host tags by id " + userId + " because it is domain-admin");
}
if (! _domainDao.isChildDomain(account.getDomainId(), domainId)) {
throw new InvalidParameterValueException("Unable to create service offering by another domain admin with id " + userId);
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
throw new InvalidParameterValueException("Unable to create service offering by id " + userId + " because it is not root-admin or domain-admin");
}
ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType); ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType);
tags = StringUtils.cleanupTags(tags); tags = StringUtils.cleanupTags(tags);
ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA,
limitResourceUse, volatileVm, displayText, typedProvisioningType, localStorageRequired, false, tags, isSystem, vmType, limitResourceUse, volatileVm, displayText, typedProvisioningType, localStorageRequired, false, tags, isSystem, vmType,
domainId, hostTag, deploymentPlanner); domainId, hostTag, deploymentPlanner);
@ -2220,6 +2244,22 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("unable to find service offering " + id); throw new InvalidParameterValueException("unable to find service offering " + id);
} }
User user = _userDao.findById(userId);
if (user == null || user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
Account account = _accountDao.findById(user.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (offeringHandle.getDomainId() == null) {
throw new InvalidParameterValueException("Unable to update public service offering by id " + userId + " because it is domain-admin");
}
if (! _domainDao.isChildDomain(account.getDomainId(), offeringHandle.getDomainId() )) {
throw new InvalidParameterValueException("Unable to update service offering by another domain admin with id " + userId);
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
throw new InvalidParameterValueException("Unable to update service offering by id " + userId + " because it is not root-admin or domain-admin");
}
boolean updateNeeded = (name != null || displayText != null || sortKey != null); boolean updateNeeded = (name != null || displayText != null || sortKey != null);
if (!updateNeeded) { if (!updateNeeded) {
return _serviceOfferingDao.findById(id); return _serviceOfferingDao.findById(id);
@ -2272,7 +2312,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
} }
} }
protected DiskOfferingVO createDiskOffering(Long domainId, String name, String description, String provisioningType, protected DiskOfferingVO createDiskOffering(Long userId, Long domainId, String name, String description, String provisioningType,
Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired, Long numGibibytes, String tags, boolean isCustomized, boolean localStorageRequired,
boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops, boolean isDisplayOfferingEnabled, Boolean isCustomizedIops, Long minIops, Long maxIops,
Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate, Long bytesReadRate, Long bytesWriteRate, Long iopsReadRate, Long iopsWriteRate,
@ -2325,6 +2365,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
maxIops = null; maxIops = null;
} }
// Check if user exists in the system
User user = _userDao.findById(userId);
if (user == null || user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
Account account = _accountDao.findById(user.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (domainId == null) {
throw new InvalidParameterValueException("Unable to create public disk offering by id " + userId + " because it is domain-admin");
}
if (tags != null) {
throw new InvalidParameterValueException("Unable to create disk offering with storage tags by id " + userId + " because it is domain-admin");
}
if (! _domainDao.isChildDomain(account.getDomainId(), domainId)) {
throw new InvalidParameterValueException("Unable to create disk offering by another domain admin with id " + userId);
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
throw new InvalidParameterValueException("Unable to create disk offering by id " + userId + " because it is not root-admin or domain-admin");
}
tags = StringUtils.cleanupTags(tags); tags = StringUtils.cleanupTags(tags);
DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, typedProvisioningType, diskSize, tags, isCustomized, DiskOfferingVO newDiskOffering = new DiskOfferingVO(domainId, name, description, typedProvisioningType, diskSize, tags, isCustomized,
isCustomizedIops, minIops, maxIops); isCustomizedIops, minIops, maxIops);
@ -2401,7 +2461,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
Long iopsWriteRate = cmd.getIopsWriteRate(); Long iopsWriteRate = cmd.getIopsWriteRate();
Integer hypervisorSnapshotReserve = cmd.getHypervisorSnapshotReserve(); Integer hypervisorSnapshotReserve = cmd.getHypervisorSnapshotReserve();
return createDiskOffering(domainId, name, description, provisioningType, numGibibytes, tags, isCustomized, Long userId = CallContext.current().getCallingUserId();
return createDiskOffering(userId, domainId, name, description, provisioningType, numGibibytes, tags, isCustomized,
localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops, localStorageRequired, isDisplayOfferingEnabled, isCustomizedIops, minIops,
maxIops, bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate, hypervisorSnapshotReserve); maxIops, bytesReadRate, bytesWriteRate, iopsReadRate, iopsWriteRate, hypervisorSnapshotReserve);
} }
@ -2422,6 +2483,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Unable to find disk offering by id " + diskOfferingId); throw new InvalidParameterValueException("Unable to find disk offering by id " + diskOfferingId);
} }
Long userId = CallContext.current().getCallingUserId();
if (userId == null) {
userId = Long.valueOf(User.UID_SYSTEM);
}
User user = _userDao.findById(userId);
if (user == null || user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
Account account = _accountDao.findById(user.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (diskOfferingHandle.getDomainId() == null) {
throw new InvalidParameterValueException("Unable to update public disk offering by id " + userId + " because it is domain-admin");
}
if (! _domainDao.isChildDomain(account.getDomainId(), diskOfferingHandle.getDomainId() )) {
throw new InvalidParameterValueException("Unable to update disk offering by another domain admin with id " + userId);
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
throw new InvalidParameterValueException("Unable to update disk offering by id " + userId + " because it is not root-admin or domain-admin");
}
boolean updateNeeded = (name != null || displayText != null || sortKey != null || displayDiskOffering != null); boolean updateNeeded = (name != null || displayText != null || sortKey != null || displayDiskOffering != null);
if (!updateNeeded) { if (!updateNeeded) {
return _diskOfferingDao.findById(diskOfferingId); return _diskOfferingDao.findById(diskOfferingId);
@ -2489,6 +2570,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Unable to find disk offering by id " + diskOfferingId); throw new InvalidParameterValueException("Unable to find disk offering by id " + diskOfferingId);
} }
Long userId = CallContext.current().getCallingUserId();
if (userId == null) {
userId = Long.valueOf(User.UID_SYSTEM);
}
User user = _userDao.findById(userId);
if (user == null || user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
Account account = _accountDao.findById(user.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (offering.getDomainId() == null) {
throw new InvalidParameterValueException("Unable to delete public disk offering by id " + userId + " because it is domain-admin");
}
if (! _domainDao.isChildDomain(account.getDomainId(), offering.getDomainId() )) {
throw new InvalidParameterValueException("Unable to delete disk offering by another domain admin with id " + userId);
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
throw new InvalidParameterValueException("Unable to delete disk offering by id " + userId + " because it is not root-admin or domain-admin");
}
offering.setState(DiskOffering.State.Inactive); offering.setState(DiskOffering.State.Inactive);
if (_diskOfferingDao.update(offering.getId(), offering)) { if (_diskOfferingDao.update(offering.getId(), offering)) {
CallContext.current().setEventDetails("Disk offering id=" + diskOfferingId); CallContext.current().setEventDetails("Disk offering id=" + diskOfferingId);
@ -2519,6 +2620,22 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Default service offerings cannot be deleted"); throw new InvalidParameterValueException("Default service offerings cannot be deleted");
} }
User user = _userDao.findById(userId);
if (user == null || user.getRemoved() != null) {
throw new InvalidParameterValueException("Unable to find active user by id " + userId);
}
Account account = _accountDao.findById(user.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) {
if (offering.getDomainId() == null) {
throw new InvalidParameterValueException("Unable to delete public service offering by id " + userId + " because it is domain-admin");
}
if (! _domainDao.isChildDomain(account.getDomainId(), offering.getDomainId() )) {
throw new InvalidParameterValueException("Unable to delete service offering by another domain admin with id " + userId);
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
throw new InvalidParameterValueException("Unable to delete service offering by id " + userId + " because it is not root-admin or domain-admin");
}
offering.setState(DiskOffering.State.Inactive); offering.setState(DiskOffering.State.Inactive);
if (_serviceOfferingDao.update(offeringId, offering)) { if (_serviceOfferingDao.update(offeringId, offering)) {
CallContext.current().setEventDetails("Service offering id=" + offeringId); CallContext.current().setEventDetails("Service offering id=" + offeringId);

View File

@ -110,6 +110,8 @@ import com.cloud.network.vpc.Vpc;
import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcManager;
import com.cloud.network.vpn.RemoteAccessVpnService; import com.cloud.network.vpn.RemoteAccessVpnService;
import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.network.vpn.Site2SiteVpnManager;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project; import com.cloud.projects.Project;
import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.projects.ProjectInvitationVO; import com.cloud.projects.ProjectInvitationVO;
@ -2616,4 +2618,36 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
public UserAccount getUserAccountById(Long userId) { public UserAccount getUserAccountById(Long userId) {
return _userAccountDao.findById(userId); return _userAccountDao.findById(userId);
} }
@Override
public void checkAccess(Account account, ServiceOffering so)
throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(account, so)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Access granted to " + account + " to " + so + " by " + checker.getName());
}
return;
}
}
assert false : "How can all of the security checkers pass on checking this caller?";
throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + so);
}
@Override
public void checkAccess(Account account, DiskOffering dof)
throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(account, dof)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Access granted to " + account + " to " + dof + " by " + checker.getName());
}
return;
}
}
assert false : "How can all of the security checkers pass on checking this caller?";
throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + dof);
}
} }

View File

@ -948,6 +948,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Check that the specified service offering ID is valid // Check that the specified service offering ID is valid
_itMgr.checkIfCanUpgrade(vmInstance, newServiceOffering); _itMgr.checkIfCanUpgrade(vmInstance, newServiceOffering);
// Check if the new service offering can be applied to vm instance
ServiceOffering newSvcOffering = _offeringDao.findById(svcOffId);
Account owner = _accountMgr.getActiveAccountById(vmInstance.getAccountId());
_accountMgr.checkAccess(owner, newSvcOffering);
_itMgr.upgradeVmDb(vmId, svcOffId); _itMgr.upgradeVmDb(vmId, svcOffId);
if (newServiceOffering.isDynamic()) { if (newServiceOffering.isDynamic()) {
//save the custom values to the database. //save the custom values to the database.
@ -2373,6 +2378,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Verify that caller can perform actions in behalf of vm owner // Verify that caller can perform actions in behalf of vm owner
_accountMgr.checkAccess(caller, null, true, owner); _accountMgr.checkAccess(caller, null, true, owner);
// Verify that owner can use the service offering
_accountMgr.checkAccess(owner, serviceOffering);
_accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId));
// Get default guest network in Basic zone // Get default guest network in Basic zone
Network defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId()); Network defaultNetwork = _networkModel.getExclusiveGuestNetwork(zone.getId());
@ -2428,6 +2437,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Verify that caller can perform actions in behalf of vm owner // Verify that caller can perform actions in behalf of vm owner
_accountMgr.checkAccess(caller, null, true, owner); _accountMgr.checkAccess(caller, null, true, owner);
// Verify that owner can use the service offering
_accountMgr.checkAccess(owner, serviceOffering);
_accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId));
// If no network is specified, find system security group enabled network // If no network is specified, find system security group enabled network
if (networkIdList == null || networkIdList.isEmpty()) { if (networkIdList == null || networkIdList.isEmpty()) {
Network networkWithSecurityGroup = _networkModel.getNetworkWithSGWithFreeIPs(zone.getId()); Network networkWithSecurityGroup = _networkModel.getNetworkWithSGWithFreeIPs(zone.getId());
@ -2532,6 +2545,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// Verify that caller can perform actions in behalf of vm owner // Verify that caller can perform actions in behalf of vm owner
_accountMgr.checkAccess(caller, null, true, owner); _accountMgr.checkAccess(caller, null, true, owner);
// Verify that owner can use the service offering
_accountMgr.checkAccess(owner, serviceOffering);
_accountMgr.checkAccess(owner, _diskOfferingDao.findById(diskOfferingId));
List<HypervisorType> vpcSupportedHTypes = _vpcMgr.getSupportedVpcHypervisors(); List<HypervisorType> vpcSupportedHTypes = _vpcMgr.getSupportedVpcHypervisors();
if (networkIdList == null || networkIdList.isEmpty()) { if (networkIdList == null || networkIdList.isEmpty()) {
NetworkVO defaultNetwork = null; NetworkVO defaultNetwork = null;

View File

@ -38,6 +38,8 @@ import com.cloud.domain.Domain;
import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.Ternary; import com.cloud.utils.Ternary;
@ -205,6 +207,16 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco
} }
@Override
public void checkAccess(Account account, ServiceOffering so) throws PermissionDeniedException {
// TODO Auto-generated method stub
}
@Override
public void checkAccess(Account account, DiskOffering dof) throws PermissionDeniedException {
// TODO Auto-generated method stub
}
@Override @Override
public Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId) { public Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

@ -24,7 +24,7 @@
if (isAdmin()) { if (isAdmin()) {
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"]; sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "system", "global-settings", "configuration", "projects", "regions", "affinityGroups"];
} else if (isDomainAdmin()) { } else if (isDomainAdmin()) {
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "regions", "affinityGroups"]; sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "domains", "events", "projects", "configuration", "regions", "affinityGroups"];
} else if (g_userProjectsEnabled) { } else if (g_userProjectsEnabled) {
sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions", "affinityGroups"]; sections = ["dashboard", "instances", "storage", "network", "templates", "accounts", "events", "projects", "regions", "affinityGroups"];
} else { //normal user } else { //normal user

View File

@ -26,6 +26,14 @@
title: 'label.menu.service.offerings', title: 'label.menu.service.offerings',
id: 'configuration', id: 'configuration',
sectionSelect: { sectionSelect: {
preFilter: function(args) {
if(isAdmin())
return ["serviceOfferings", "systemServiceOfferings", "diskOfferings", "networkOfferings"];
else if(isDomainAdmin())
return ["serviceOfferings", "diskOfferings"];
else
return null;
},
label: 'label.select.offering' label: 'label.select.offering'
}, },
sections: { sections: {
@ -62,6 +70,17 @@
createForm: { createForm: {
title: 'label.add.compute.offering', title: 'label.add.compute.offering',
preFilter: function(args) {
if (isAdmin()) {
} else {
args.$form.find('.form-item[rel=isPublic]').hide();
args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown
args.$form.find('.form-item[rel=deploymentPlanner]').hide();
args.$form.find('.form-item[rel=plannerMode]').hide();
args.$form.find('.form-item[rel=storageTags]').hide();
args.$form.find('.form-item[rel=hostTags]').hide();
}
},
fields: { fields: {
name: { name: {
label: 'label.name', label: 'label.name',
@ -385,7 +404,7 @@
label: 'label.public', label: 'label.public',
isBoolean: true, isBoolean: true,
isReverse: true, isReverse: true,
isChecked: true, isChecked: false,
docID: 'helpComputeOfferingPublic' docID: 'helpComputeOfferingPublic'
}, },
@ -399,6 +418,7 @@
deploymentPlanner: { deploymentPlanner: {
label: 'label.deployment.planner', label: 'label.deployment.planner',
select: function(args) { select: function(args) {
if (isAdmin()) {
$.ajax({ $.ajax({
url: createURL('listDeploymentPlanners'), url: createURL('listDeploymentPlanners'),
dataType: 'json', dataType: 'json',
@ -429,6 +449,7 @@
} }
}); });
} }
}
}, },
// plannerKey:{label:'Planner Key' , docID:'helpImplicitPlannerKey'}, // plannerKey:{label:'Planner Key' , docID:'helpImplicitPlannerKey'},
@ -761,7 +782,7 @@
}); });
$.ajax({ $.ajax({
url: createURL('listServiceOfferings'), url: createURL('listServiceOfferings&isrecursive=true'),
data: data, data: data,
success: function(json) { success: function(json) {
var items = json.listserviceofferingsresponse.serviceoffering; var items = json.listserviceofferingsresponse.serviceoffering;
@ -975,7 +996,7 @@
id: args.context.serviceOfferings[0].id id: args.context.serviceOfferings[0].id
}; };
$.ajax({ $.ajax({
url: createURL('listServiceOfferings'), url: createURL('listServiceOfferings&isrecursive=true'),
data: data, data: data,
async: true, async: true,
success: function(json) { success: function(json) {
@ -1038,6 +1059,13 @@
createForm: { createForm: {
title: 'label.add.system.service.offering', title: 'label.add.system.service.offering',
preFilter: function(args) {
if (isAdmin()) {
} else {
args.$form.find('.form-item[rel=isPublic]').hide();
args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown
}
},
fields: { fields: {
name: { name: {
label: 'label.name', label: 'label.name',
@ -1203,7 +1231,7 @@
label: 'label.public', label: 'label.public',
isBoolean: true, isBoolean: true,
isReverse: true, isReverse: true,
isChecked: true, isChecked: false,
docID: 'helpSystemOfferingPublic' docID: 'helpSystemOfferingPublic'
}, },
domainId: { domainId: {
@ -1332,7 +1360,7 @@
}); });
$.ajax({ $.ajax({
url: createURL('listServiceOfferings'), url: createURL('listServiceOfferings&isrecursive=true'),
data: data, data: data,
success: function(json) { success: function(json) {
var items = json.listserviceofferingsresponse.serviceoffering; var items = json.listserviceofferingsresponse.serviceoffering;
@ -1515,7 +1543,7 @@
id: args.context.systemServiceOfferings[0].id id: args.context.systemServiceOfferings[0].id
}; };
$.ajax({ $.ajax({
url: createURL('listServiceOfferings'), url: createURL('listServiceOfferings&isrecursive=true'),
data: data, data: data,
success: function(json) { success: function(json) {
var item = json.listserviceofferingsresponse.serviceoffering[0]; var item = json.listserviceofferingsresponse.serviceoffering[0];
@ -1567,7 +1595,7 @@
listViewDataProvider(args, data); listViewDataProvider(args, data);
$.ajax({ $.ajax({
url: createURL('listDiskOfferings'), url: createURL('listDiskOfferings&isrecursive=true'),
data: data, data: data,
success: function(json) { success: function(json) {
var items = json.listdiskofferingsresponse.diskoffering; var items = json.listdiskofferingsresponse.diskoffering;
@ -1596,6 +1624,14 @@
createForm: { createForm: {
title: 'label.add.disk.offering', title: 'label.add.disk.offering',
preFilter: function(args) {
if (isAdmin()) {
} else {
args.$form.find('.form-item[rel=isPublic]').hide();
args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown
args.$form.find('.form-item[rel=tags]').hide();
}
},
fields: { fields: {
name: { name: {
label: 'label.name', label: 'label.name',
@ -1868,7 +1904,7 @@
label: 'label.public', label: 'label.public',
isBoolean: true, isBoolean: true,
isReverse: true, isReverse: true,
isChecked: true, isChecked: false,
docID: 'helpDiskOfferingPublic' docID: 'helpDiskOfferingPublic'
}, },
domainId: { domainId: {
@ -2165,7 +2201,7 @@
id: args.context.diskOfferings[0].id id: args.context.diskOfferings[0].id
}; };
$.ajax({ $.ajax({
url: createURL('listDiskOfferings'), url: createURL('listDiskOfferings&isrecursive=true'),
data: data, data: data,
success: function(json) { success: function(json) {
var item = json.listdiskofferingsresponse.diskoffering[0]; var item = json.listdiskofferingsresponse.diskoffering[0];