server: update network offering for specified domain(s) & zone(s)

Added checkAccess while creating network from offering.
Response fixes for networkoffering APIs.

Signed-off-by: Abhishek Kumar <abhishek.kumar@shapeblue.com>
This commit is contained in:
Abhishek Kumar 2019-04-11 17:56:34 +05:30 committed by Abhishek Kumar
parent eaa759209a
commit c671e07c18
11 changed files with 218 additions and 77 deletions

View File

@ -29,6 +29,7 @@ import com.cloud.dc.DataCenter;
import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
public interface AccountService {
@ -101,6 +102,8 @@ public interface AccountService {
void checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException;
void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException;
void checkAccess(User user, ControlledEntity entity);
void checkAccess(Account account, AccessType accessType, boolean sameOwner, String apiName, ControlledEntity... entities) throws PermissionDeniedException;

View File

@ -20,6 +20,7 @@ import com.cloud.dc.DataCenter;
import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.user.Account;
import com.cloud.user.User;
@ -139,4 +140,6 @@ public interface SecurityChecker extends Adapter {
boolean checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException;
boolean checkAccess(Account account, DiskOffering dof, DataCenter zone) throws PermissionDeniedException;
boolean checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException;
}

View File

@ -171,6 +171,7 @@ import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
@ -286,6 +287,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
RemoteAccessVpnDao _remoteAccessVpnDao;
@Inject
VpcVirtualNetworkApplianceService _routerService;
@Inject
AccountManager accountManager;
List<NetworkGuru> networkGurus;
@ -2162,6 +2165,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
final DataCenterVO zone = _dcDao.findById(zoneId);
accountManager.checkAccess(owner, ntwkOff, zone);
// this method supports only guest network creation
if (ntwkOff.getTrafficType() != TrafficType.Guest) {
s_logger.warn("Only guest networks can be created using this method");
@ -2196,7 +2201,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
ipv6 = true;
}
// Validate zone
final DataCenterVO zone = _dcDao.findById(zoneId);
if (zone.getNetworkType() == NetworkType.Basic) {
// In Basic zone the network should have aclType=Domain, domainId=1, subdomainAccess=true
if (aclType == null || aclType != ACLType.Domain) {

View File

@ -54,11 +54,11 @@ public class NetworkOfferingDetailsVO implements ResourceDetail {
public NetworkOfferingDetailsVO() {
}
public NetworkOfferingDetailsVO(long resourceId, Detail detailName, String value) {
public NetworkOfferingDetailsVO(long resourceId, Detail detailName, String value, boolean display) {
this.resourceId = resourceId;
this.name = detailName;
this.value = value;
this.display = false;
this.display = display;
}
@Override

View File

@ -23,7 +23,6 @@ import java.util.Map;
import javax.inject.Inject;
import javax.persistence.EntityExistsException;
import com.cloud.offerings.NetworkOfferingServiceMapVO;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
@ -33,6 +32,7 @@ import com.cloud.offering.NetworkOffering;
import com.cloud.offering.NetworkOffering.Availability;
import com.cloud.offering.NetworkOffering.Detail;
import com.cloud.offerings.NetworkOfferingDetailsVO;
import com.cloud.offerings.NetworkOfferingServiceMapVO;
import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
@ -187,7 +187,7 @@ public class NetworkOfferingDaoImpl extends GenericDaoBase<NetworkOfferingVO, Lo
//2) persist the details
if (details != null && !details.isEmpty()) {
for (NetworkOffering.Detail detail : details.keySet()) {
_detailsDao.persist(new NetworkOfferingDetailsVO(off.getId(), detail, details.get(detail)));
_detailsDao.persist(new NetworkOfferingDetailsVO(off.getId(), detail, details.get(detail), true));
}
}

View File

@ -43,12 +43,14 @@ public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase<Networ
DetailSearch.and("resourceId", DetailSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
DetailSearch.and("name", DetailSearch.entity().getName(), SearchCriteria.Op.EQ);
DetailSearch.and("value", DetailSearch.entity().getValue(), SearchCriteria.Op.EQ);
DetailSearch.and("display", DetailSearch.entity().isDisplay(), SearchCriteria.Op.EQ);
DetailSearch.done();
ValueSearch = createSearchBuilder(String.class);
ValueSearch.select(null, Func.DISTINCT, ValueSearch.entity().getValue());
ValueSearch.and("resourceId", ValueSearch.entity().getResourceId(), SearchCriteria.Op.EQ);
ValueSearch.and("name", ValueSearch.entity().getName(), Op.EQ);
ValueSearch.and("display", ValueSearch.entity().isDisplay(), SearchCriteria.Op.EQ);
ValueSearch.done();
}
@ -56,6 +58,7 @@ public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase<Networ
public Map<NetworkOffering.Detail, String> getNtwkOffDetails(long offeringId) {
SearchCriteria<NetworkOfferingDetailsVO> sc = DetailSearch.create();
sc.setParameters("resourceId", offeringId);
sc.setParameters("display", true);
List<NetworkOfferingDetailsVO> results = search(sc, null);
Map<NetworkOffering.Detail, String> details = new HashMap<NetworkOffering.Detail, String>(results.size());
@ -81,7 +84,7 @@ public class NetworkOfferingDetailsDaoImpl extends ResourceDetailsDaoBase<Networ
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
persist(new NetworkOfferingDetailsVO(resourceId, Detail.valueOf(key), value));
persist(new NetworkOfferingDetailsVO(resourceId, Detail.valueOf(key), value, display));
}
@Override

View File

@ -35,7 +35,9 @@ import com.cloud.exception.PermissionDeniedException;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
import com.cloud.projects.ProjectManager;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao;
@ -71,6 +73,8 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
DiskOfferingDetailsDao diskOfferingDetailsDao;
@Inject
ServiceOfferingDetailsDao serviceOfferingDetailsDao;
@Inject
NetworkOfferingDetailsDao networkserviceOfferingDetailsDao;
protected DomainChecker() {
super();
@ -249,6 +253,44 @@ public class DomainChecker extends AdapterBase implements SecurityChecker {
return isAccess;
}
@Override
public boolean checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException {
boolean isAccess = false;
// Check fo domains
if (account == null || nof == null) {
isAccess = true;
} else {
//admin has all permissions
if (_accountService.isRootAdmin(account.getId())) {
isAccess = true;
}
//if account is normal user or domain admin
//check if account's domain is a child of offering's domain (Note: This is made consistent with the list command for disk offering)
else if (_accountService.isNormalUser(account.getId())
|| account.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN
|| _accountService.isDomainAdmin(account.getId())
|| account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
final List<Long> doDomainIds = networkserviceOfferingDetailsDao.findDomainIds(nof.getId());
if (doDomainIds.isEmpty()) {
isAccess = true;
} else {
for (Long domainId : doDomainIds) {
if (_domainDao.isChildDomain(domainId, account.getDomainId())) {
isAccess = true;
break;
}
}
}
}
}
// Check for zones
if (isAccess && nof != null && zone != null) {
final List<Long> doZoneIds = networkserviceOfferingDetailsDao.findZoneIds(nof.getId());
isAccess = doZoneIds.isEmpty() || doZoneIds.contains(zone.getId());
}
return isAccess;
}
@Override
public boolean checkAccess(Account account, DataCenter zone) throws PermissionDeniedException {
if (account == null || zone.getDomainId() == null) {//public zone

View File

@ -175,6 +175,7 @@ import com.cloud.api.query.vo.EventJoinVO;
import com.cloud.api.query.vo.HostJoinVO;
import com.cloud.api.query.vo.ImageStoreJoinVO;
import com.cloud.api.query.vo.InstanceGroupJoinVO;
import com.cloud.api.query.vo.NetworkOfferingJoinVO;
import com.cloud.api.query.vo.ProjectAccountJoinVO;
import com.cloud.api.query.vo.ProjectInvitationJoinVO;
import com.cloud.api.query.vo.ProjectJoinVO;
@ -1913,6 +1914,9 @@ public class ApiResponseHelper implements ResponseGenerator {
@Override
public NetworkOfferingResponse createNetworkOfferingResponse(NetworkOffering offering) {
if (!(offering instanceof NetworkOfferingJoinVO)) {
offering = ApiDBUtils.newNetworkOfferingView(offering);
}
NetworkOfferingResponse response = ApiDBUtils.newNetworkOfferingResponse(offering);
response.setNetworkRate(ApiDBUtils.getNetworkRate(offering.getId()));
Long so = null;

View File

@ -2631,12 +2631,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
for (Long domainId : existingDomainIds) {
if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) {
throw new InvalidParameterValueException("Unable to update disk service by another domain admin with id " + userId);
throw new InvalidParameterValueException("Unable to update service by another domain admin with id " + userId);
}
}
for (Long domainId : filteredDomainIds) {
if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) {
throw new InvalidParameterValueException("Unable to update disk service by another domain admin with id " + userId);
throw new InvalidParameterValueException("Unable to update service by another domain admin with id " + userId);
}
}
} else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) {
@ -5135,11 +5135,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
List<NetworkOfferingDetailsVO> detailsVO = new ArrayList<>();
for (Long domainId : filteredDomainIds) {
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.domainid, String.valueOf(domainId)));
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.domainid, String.valueOf(domainId), false));
}
if (CollectionUtils.isNotEmpty(zoneIds)) {
for (Long zoneId : zoneIds) {
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.zoneid, String.valueOf(zoneId)));
detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.zoneid, String.valueOf(zoneId), false));
}
}
if (!detailsVO.isEmpty()) {
@ -5507,10 +5507,13 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
Availability availability = null;
final String state = cmd.getState();
final String tags = cmd.getTags();
final List<Long> domainIds = cmd.getDomainIds();
final List<Long> zoneIds = cmd.getZoneIds();
CallContext.current().setEventDetails(" Id: " + id);
// Verify input parameters
final NetworkOfferingVO offeringToUpdate = _networkOfferingDao.findById(id);
List<Long> existingDomainIds = networkOfferingDetailsDao.findDomainIds(id);
if (offeringToUpdate == null) {
throw new InvalidParameterValueException("unable to find network offering " + id);
}
@ -5520,8 +5523,51 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Can't update system network offerings");
}
// check if valid domain
if (CollectionUtils.isNotEmpty(domainIds)) {
for (final Long domainId: domainIds) {
if (_domainDao.findById(domainId) == null) {
throw new InvalidParameterValueException("Please specify a valid domain id");
}
}
}
// check if valid zone
if (CollectionUtils.isNotEmpty(zoneIds)) {
for (Long zoneId : zoneIds) {
if (_zoneDao.findById(zoneId) == null)
throw new InvalidParameterValueException("Please specify a valid zone id");
}
}
// Filter child domains when both parent and child domains are present
List<Long> filteredDomainIds = filterChildSubDomains(domainIds);
if (CollectionUtils.isNotEmpty(existingDomainIds) && CollectionUtils.isNotEmpty(filteredDomainIds)) {
filteredDomainIds.removeIf(existingDomainIds::contains);
for (Long domainId : filteredDomainIds) {
for (Long existingDomainId : existingDomainIds) {
if (_domainDao.isChildDomain(existingDomainId, domainId)) {
throw new InvalidParameterValueException("Unable to update network offering for domain " + _domainDao.findById(domainId).getUuid() + " as offering is already available for parent domain");
}
}
}
}
List<Long> filteredZoneIds = new ArrayList<>();
if (CollectionUtils.isNotEmpty(zoneIds)) {
filteredZoneIds.addAll(zoneIds);
List<Long> existingZoneIds = networkOfferingDetailsDao.findZoneIds(id);
if (CollectionUtils.isNotEmpty(existingZoneIds)) {
filteredZoneIds.removeIf(existingZoneIds::contains);
}
}
final NetworkOfferingVO offering = _networkOfferingDao.createForUpdate(id);
boolean updateNeeded = name != null || displayText != null || sortKey != null ||
state != null || tags != null || availabilityStr != null || maxconn != null;
if(updateNeeded) {
if (name != null) {
offering.setName(name);
}
@ -5600,13 +5646,27 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
}
if (_networkOfferingDao.update(id, offering)) {
return _networkOfferingDao.findById(id);
} else {
if (!_networkOfferingDao.update(id, offering)) {
return null;
}
}
List<NetworkOfferingDetailsVO> detailsVO = new ArrayList<>();
for (Long domainId : filteredDomainIds) {
detailsVO.add(new NetworkOfferingDetailsVO(id, Detail.domainid, String.valueOf(domainId), false));
}
for (Long zoneId : filteredZoneIds) {
detailsVO.add(new NetworkOfferingDetailsVO(id, Detail.zoneid, String.valueOf(zoneId), false));
}
if (!detailsVO.isEmpty()) {
for (NetworkOfferingDetailsVO detailVO : detailsVO) {
networkOfferingDetailsDao.persist(detailVO);
}
}
return _networkOfferingDao.findById(id);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_MARK_DEFAULT_ZONE, eventDescription = "Marking account with the " + "default zone", async = true)
public AccountVO markDefaultZone(final String accountName, final long domainId, final long defaultZoneId) {

View File

@ -118,6 +118,7 @@ import com.cloud.network.vpc.VpcManager;
import com.cloud.network.vpn.RemoteAccessVpnService;
import com.cloud.network.vpn.Site2SiteVpnManager;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
@ -2859,6 +2860,21 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
throw new PermissionDeniedException("There's no way to confirm " + account + " has access to " + dof);
}
@Override
public void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {
if (checker.checkAccess(account, nof, zone)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Access granted to " + account + " to " + nof + " 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 " + nof);
}
@Override
public void checkAccess(User user, ControlledEntity entity) throws PermissionDeniedException {
for (SecurityChecker checker : _securityCheckers) {

View File

@ -42,6 +42,7 @@ import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.offering.DiskOffering;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.ServiceOffering;
import com.cloud.projects.Project.ListProjectResourcesCriteria;
import com.cloud.utils.Pair;
@ -222,6 +223,11 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco
// TODO Auto-generated method stub
}
@Override
public void checkAccess(Account account, NetworkOffering nof, DataCenter zone) throws PermissionDeniedException {
// TODO Auto-generated method stub
}
@Override
public Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId) {
// TODO Auto-generated method stub