From 9f46efef02bda2a5716200680782edc36ba07848 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 9 Apr 2019 10:55:57 +0530 Subject: [PATCH] server update service, disk offerings for domain(s) and zone(s) updateServiceOffering and updateDiskOffering API has been modified to allow updating domain(s) and zone(s) for the offering. Signed-off-by: Abhishek Kumar --- .../admin/offering/CreateDiskOfferingCmd.java | 13 ++ .../offering/CreateServiceOfferingCmd.java | 13 ++ .../admin/offering/UpdateDiskOfferingCmd.java | 40 +++++ .../offering/UpdateServiceOfferingCmd.java | 41 ++++- .../ConfigurationManagerImpl.java | 148 ++++++++++++++++-- 5 files changed, 238 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java index 536e4c47b87..41d71c821c6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateDiskOfferingCmd.java @@ -16,7 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.admin.offering; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -27,6 +29,7 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.offering.DiskOffering; @@ -178,10 +181,20 @@ public class CreateDiskOfferingCmd extends BaseCmd { } public List getDomainIds() { + if(CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } return domainIds; } public List getZoneIds() { + if(CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } return zoneIds; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java index ec94355d419..347e3308b26 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/CreateServiceOfferingCmd.java @@ -18,8 +18,10 @@ package org.apache.cloudstack.api.command.admin.offering; import java.util.Collection; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -31,6 +33,7 @@ import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.commons.collections.MapUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.exception.InvalidParameterValueException; @@ -261,10 +264,20 @@ public class CreateServiceOfferingCmd extends BaseCmd { } public List getDomainIds() { + if(CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } return domainIds; } public List getZoneIds() { + if(CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } return zoneIds; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java index 55d1add370c..b179c26bd3a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateDiskOfferingCmd.java @@ -16,6 +16,10 @@ // under the License. package org.apache.cloudstack.api.command.admin.offering; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -23,6 +27,9 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DiskOfferingResponse; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.cloud.offering.DiskOffering; @@ -58,6 +65,21 @@ public class UpdateDiskOfferingCmd extends BaseCmd { description = "an optional field, whether to display the offering to the end user or not.") private Boolean displayOffering; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "the ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -82,6 +104,24 @@ public class UpdateDiskOfferingCmd extends BaseCmd { return displayOffering; } + public List getDomainIds() { + if(CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } + return domainIds; + } + + public List getZoneIds() { + if(CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } + return zoneIds; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java index f4f4bdfac88..4d70edad8be 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/offering/UpdateServiceOfferingCmd.java @@ -16,7 +16,9 @@ // under the License. package org.apache.cloudstack.api.command.admin.offering; -import org.apache.log4j.Logger; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; @@ -24,7 +26,11 @@ import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.commons.collections.CollectionUtils; +import org.apache.log4j.Logger; import com.cloud.offering.ServiceOffering; import com.cloud.user.Account; @@ -54,6 +60,21 @@ public class UpdateServiceOfferingCmd extends BaseCmd { @Parameter(name = ApiConstants.SORT_KEY, type = CommandType.INTEGER, description = "sort key of the service offering, integer") private Integer sortKey; + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = DomainResponse.class, + description = "the ID of the containing domain(s), null for public offerings") + private List domainIds; + + @Parameter(name = ApiConstants.ZONE_ID, + type = CommandType.LIST, + collectionType = CommandType.UUID, + entityType = ZoneResponse.class, + description = "the ID of the containing zone(s), null for public offerings", + since = "4.13") + private List zoneIds; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -74,6 +95,24 @@ public class UpdateServiceOfferingCmd extends BaseCmd { return sortKey; } + public List getDomainIds() { + if(CollectionUtils.isNotEmpty(domainIds)) { + Set set = new LinkedHashSet<>(domainIds); + domainIds.clear(); + domainIds.addAll(set); + } + return domainIds; + } + + public List getZoneIds() { + if(CollectionUtils.isNotEmpty(zoneIds)) { + Set set = new LinkedHashSet<>(zoneIds); + zoneIds.clear(); + zoneIds.addAll(set); + } + return zoneIds; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 617f96bed76..5adaaacc6ed 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -2555,6 +2555,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final String name = cmd.getServiceOfferingName(); final Integer sortKey = cmd.getSortKey(); Long userId = CallContext.current().getCallingUserId(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); if (userId == null) { userId = Long.valueOf(User.UID_SYSTEM); @@ -2562,25 +2564,69 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Verify input parameters final ServiceOffering offeringHandle = _entityMgr.findById(ServiceOffering.class, id); + List existingDomainIds = _serviceOfferingDetailsDao.findDomainIds(id); if (offeringHandle == null) { throw new InvalidParameterValueException("unable to find service offering " + id); } + // 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"); + } + } + final User user = _userDao.findById(userId); if (user == null || user.getRemoved() != null) { throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); + + // Filter child domains when both parent and child domains are present + List 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 service offering for domain " + _domainDao.findById(domainId).getUuid() + " as offering is already available for parent domain"); + } + } + } + } + + List filteredZoneIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(zoneIds)) { + filteredZoneIds.addAll(zoneIds); + List existingZoneIds = _serviceOfferingDetailsDao.findZoneIds(id); + if (CollectionUtils.isNotEmpty(existingZoneIds)) { + filteredZoneIds.removeIf(existingZoneIds::contains); + } + } + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { - final List details = _serviceOfferingDetailsDao.findDetails(offeringHandle.getId(), ApiConstants.DOMAIN_ID); - if (details.isEmpty()) { + if (existingDomainIds.isEmpty()) { throw new InvalidParameterValueException("Unable to update public service offering by id " + userId + " because it is domain-admin"); } - for (final ServiceOfferingDetailsVO detail : details) { - final Long domainId = Long.valueOf(detail.getValue(), 0); + for (Long domainId : existingDomainIds) { if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { - throw new InvalidParameterValueException("Unable to update service offering by another domain admin with id " + userId); + throw new InvalidParameterValueException("Unable to update disk 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); } } } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { @@ -2588,7 +2634,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final boolean updateNeeded = name != null || displayText != null || sortKey != null; - if (!updateNeeded) { + final boolean detailsUpdateNeeded = !filteredDomainIds.isEmpty() || !filteredZoneIds.isEmpty(); + if (!updateNeeded && !detailsUpdateNeeded) { return _serviceOfferingDao.findById(id); } @@ -2630,13 +2677,24 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // } // } - if (_serviceOfferingDao.update(id, offering)) { - offering = _serviceOfferingDao.findById(id); - CallContext.current().setEventDetails("Service offering id=" + offering.getId()); - return offering; - } else { + if (updateNeeded && !_serviceOfferingDao.update(id, offering)) { return null; } + List detailsVO = new ArrayList<>(); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new ServiceOfferingDetailsVO(id, ApiConstants.DOMAIN_ID, String.valueOf(domainId), true)); + } + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new ServiceOfferingDetailsVO(id, ApiConstants.ZONE_ID, String.valueOf(zoneId), true)); + } + if (!detailsVO.isEmpty()) { + for (ServiceOfferingDetailsVO detailVO : detailsVO) { + _serviceOfferingDetailsDao.persist(detailVO); + } + } + offering = _serviceOfferingDao.findById(id); + CallContext.current().setEventDetails("Service offering id=" + offering.getId()); + return offering; } protected DiskOfferingVO createDiskOffering(final Long userId, final List domainIds, final List zoneIds, final String name, final String description, final String provisioningType, @@ -2861,6 +2919,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final String displayText = cmd.getDisplayText(); final Integer sortKey = cmd.getSortKey(); final Boolean displayDiskOffering = cmd.getDisplayOffering(); + final List domainIds = cmd.getDomainIds(); + final List zoneIds = cmd.getZoneIds(); // Check if diskOffering exists final DiskOffering diskOfferingHandle = _entityMgr.findById(DiskOffering.class, diskOfferingId); @@ -2870,6 +2930,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Unable to find disk offering by id " + diskOfferingId); } + // 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"); + } + } + Long userId = CallContext.current().getCallingUserId(); if (userId == null) { userId = Long.valueOf(User.UID_SYSTEM); @@ -2880,6 +2957,28 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final Account account = _accountDao.findById(user.getAccountId()); + // Filter child domains when both parent and child domains are present + List 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 disk offering for domain " + _domainDao.findById(domainId).getUuid() + " as offering is already available for parent domain"); + } + } + } + } + + List filteredZoneIds = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(zoneIds)) { + filteredZoneIds.addAll(zoneIds); + List existingZoneIds = _serviceOfferingDetailsDao.findZoneIds(diskOfferingId); + if (CollectionUtils.isNotEmpty(existingZoneIds)) { + filteredZoneIds.removeIf(existingZoneIds::contains); + } + } + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { if (existingDomainIds.isEmpty()) { throw new InvalidParameterValueException("Unable to update public disk offering by id " + userId + " because it is domain-admin"); @@ -2889,12 +2988,18 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Unable to update disk offering by another domain admin with id " + userId); } } + for (Long domainId : filteredDomainIds) { + if (!_domainDao.isChildDomain(account.getDomainId(), domainId)) { + 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"); } final boolean updateNeeded = name != null || displayText != null || sortKey != null || displayDiskOffering != null; - if (!updateNeeded) { + final boolean detailsUpdateNeeded = !filteredDomainIds.isEmpty() || !filteredZoneIds.isEmpty(); + if (!updateNeeded && !detailsUpdateNeeded) { return _diskOfferingDao.findById(diskOfferingId); } @@ -2941,12 +3046,23 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // } // } - if (_diskOfferingDao.update(diskOfferingId, diskOffering)) { - CallContext.current().setEventDetails("Disk offering id=" + diskOffering.getId()); - return _diskOfferingDao.findById(diskOfferingId); - } else { + if (updateNeeded && !_diskOfferingDao.update(diskOfferingId, diskOffering)) { return null; } + List detailsVO = new ArrayList<>(); + for (Long domainId : filteredDomainIds) { + detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), true)); + } + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.ZONE_ID, String.valueOf(zoneId), true)); + } + if (!detailsVO.isEmpty()) { + for (DiskOfferingDetailVO detailVO : detailsVO) { + diskOfferingDetailsDao.persist(detailVO); + } + } + CallContext.current().setEventDetails("Disk offering id=" + diskOffering.getId()); + return _diskOfferingDao.findById(diskOfferingId); } @Override