/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource; import static com.emc.storageos.api.mapper.ComputeMapper.map; import static com.emc.storageos.api.mapper.ComputeVirtualPoolMapper.toComputeVirtualPool; import static com.emc.storageos.api.mapper.ComputeVirtualPoolMapper.toUriList; import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.api.service.authorization.PermissionsHelper; import com.emc.storageos.api.service.impl.resource.utils.GeoVisibilityHelper; import com.emc.storageos.api.service.impl.response.BulkList; import com.emc.storageos.api.service.impl.response.ResRepFilter; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.ComputeElement; import com.emc.storageos.db.client.model.ComputeVirtualPool; import com.emc.storageos.db.client.model.Cluster; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.TenantOrg; import com.emc.storageos.db.client.model.UCSServiceProfileTemplate; import com.emc.storageos.db.client.model.VirtualArray; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.model.BulkIdParam; import com.emc.storageos.model.RelatedResourceRep; import com.emc.storageos.model.ResourceTypeEnum; import com.emc.storageos.model.auth.ACLAssignmentChanges; import com.emc.storageos.model.auth.ACLAssignments; import com.emc.storageos.model.compute.ComputeElementListRestRep; import com.emc.storageos.model.compute.ComputeElementRestRep; import com.emc.storageos.model.compute.ComputeSystemBulkRep; import com.emc.storageos.model.compute.ComputeSystemRestRep; import com.emc.storageos.model.pools.VirtualArrayAssignmentChanges; import com.emc.storageos.model.pools.VirtualArrayAssignments; import com.emc.storageos.model.vpool.ComputeVirtualPoolBulkRep; import com.emc.storageos.model.vpool.ComputeVirtualPoolCreateParam; import com.emc.storageos.model.vpool.ComputeVirtualPoolElementUpdateParam; import com.emc.storageos.model.vpool.ComputeVirtualPoolList; import com.emc.storageos.model.vpool.ComputeVirtualPoolRestRep; import com.emc.storageos.model.vpool.ComputeVirtualPoolUpdateParam; import com.emc.storageos.model.vpool.ServiceProfileTemplateAssignmentChanges; import com.emc.storageos.model.vpool.ServiceProfileTemplateAssignments; import com.emc.storageos.security.authentication.StorageOSUser; import com.emc.storageos.security.authorization.ACL; import com.emc.storageos.security.authorization.CheckPermission; import com.emc.storageos.security.authorization.DefaultPermissions; import com.emc.storageos.security.authorization.Role; import com.emc.storageos.services.OperationTypeEnum; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.volumecontroller.impl.ControllerUtils; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableBourneEvent; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager; import com.emc.storageos.volumecontroller.impl.monitoring.cim.enums.RecordType; import com.google.common.base.Function; import com.google.common.collect.Lists; @Path("/compute/vpools") @DefaultPermissions(readRoles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, readAcls = { ACL.USE }, writeRoles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public class ComputeVirtualPoolService extends TaggedResource { protected static final String EVENT_SERVICE_TYPE = "COMPUTE_VPOOL"; protected static final String EVENT_SERVICE_SOURCE = "ComputeVirtualPoolService"; protected static final String VPOOL_CREATED_DESCRIPTION = "Compute Virtual Pool Created"; protected static final String VPOOL_UPDATED_DESCRIPTION = "Compute Virtual Pool Updated"; protected static final String VPOOL_DELETED_DESCRIPTION = "Compute Virtual Pool Deleted"; private static final Logger _log = LoggerFactory.getLogger(ComputeVirtualPoolService.class); @Autowired protected GeoVisibilityHelper _geoHelper; @Autowired private RecordableEventManager _evtMgr; @Autowired private ComputeSystemService computeSystemService; @Autowired private VirtualArrayService virtualArrayService; @Override public String getServiceType() { return EVENT_SERVICE_TYPE; } @Override protected DataObject queryResource(URI id) { ComputeVirtualPool cvp = _permissionsHelper.getObjectById(id, ComputeVirtualPool.class); ArgValidator.checkEntityNotNull(cvp, id, isIdEmbeddedInURL(id)); return cvp; } @Override protected URI getTenantOwner(URI id) { return null; } @Override protected ResourceTypeEnum getResourceType() { return ResourceTypeEnum.COMPUTE_VPOOL; } @SuppressWarnings("unchecked") @Override public Class<ComputeVirtualPool> getResourceClass() { return ComputeVirtualPool.class; } /** * Get compute virtual pool by ID * * @brief Get compute virtual pool by ID * @param id the URN of a Compute Virtual Pool * @return ComputeVirtualPoolRestRep representation of Compute Virtual Pool */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE }) public ComputeVirtualPoolRestRep getComputeVirtualPool(@PathParam("id") URI id) { ArgValidator.checkUri(id); ComputeVirtualPool cvp = _permissionsHelper.getObjectById(id, ComputeVirtualPool.class); ArgValidator.checkEntityNotNull(cvp, id, isIdEmbeddedInURL(id)); return toComputeVirtualPool(_dbClient, cvp, isComputeVirtualPoolInUse(cvp)); } /** * Get all compute virtual pools * * @brief Get all compute virtual pools * @return ComputeVirtualPoolList representations of Compute Virtual Pools */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public ComputeVirtualPoolList getComputeVirtualPool( @DefaultValue("") @QueryParam(TENANT_ID_QUERY_PARAM) String tenantId) { List<URI> ids = _dbClient.queryByType(ComputeVirtualPool.class, true); ComputeVirtualPoolList list = new ComputeVirtualPoolList(); // if input tenant is not empty, but user have no access to it, an exception will be thrown. TenantOrg tenant_input = null; if (!StringUtils.isEmpty(tenantId)) { tenant_input = getTenantIfHaveAccess(tenantId); } StorageOSUser user = getUserFromContext(); Iterator<ComputeVirtualPool> iter = _dbClient.queryIterativeObjects(ComputeVirtualPool.class, ids); List<ComputeVirtualPool> vpoolObjects = new ArrayList<>(); while (iter.hasNext()) { vpoolObjects.add(iter.next()); } // full list if role is {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR} AND no tenant restriction from input // else only return the list, which input tenant has access. if (_permissionsHelper.userHasGivenRole(user, null, Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR)) { for (ComputeVirtualPool virtualPool : vpoolObjects) { if (tenant_input == null || _permissionsHelper.tenantHasUsageACL(tenant_input.getId(), virtualPool)) { list.getComputeVirtualPool().add(toNamedRelatedResource(virtualPool)); } } } else { // otherwise, filter by only authorized to use URI tenant = null; if (tenant_input == null) { tenant = URI.create(user.getTenantId()); } else { tenant = tenant_input.getId(); } Set<ComputeVirtualPool> vpoolSet = new HashSet<ComputeVirtualPool>(); for (ComputeVirtualPool virtualPool : vpoolObjects) { if (_permissionsHelper.tenantHasUsageACL(tenant, virtualPool)) { vpoolSet.add(virtualPool); } } // if no tenant specified in request, also adding vpools which sub-tenants of the user have access to. if (tenant_input == null) { List<URI> subtenants = _permissionsHelper.getSubtenantsWithRoles(user); for (ComputeVirtualPool virtualPool : vpoolObjects) { if (_permissionsHelper.tenantHasUsageACL(subtenants, virtualPool)) { vpoolSet.add(virtualPool); } } } for (ComputeVirtualPool virtualPool : vpoolSet) { list.getComputeVirtualPool().add(toNamedRelatedResource(virtualPool)); } } return list; } private ComputeVirtualPool constructAndValidateComputeVirtualPool(ComputeVirtualPoolCreateParam param) throws DatabaseException { // Initial Validations if (param.getSystemType() != null) { ArgValidator.checkFieldValueFromEnum(param.getSystemType(), "system_type", ComputeVirtualPool.SupportedSystemTypes.class); } else { throw APIException.badRequests.requiredParameterMissingOrEmpty("system_type"); } validateMinMaxIntValues(param.getMinProcessors(), param.getMaxProcessors(), "min_processors", "max_processors"); validateMinMaxIntValues(param.getMinTotalCores(), param.getMaxTotalCores(), "min_total_cores", "max_total_cores"); validateMinMaxIntValues(param.getMinTotalThreads(), param.getMaxTotalThreads(), "min_total_threads", "max_total_threads"); validateMinMaxIntValues(param.getMinCpuSpeed(), param.getMaxCpuSpeed(), "min_cpu_speed", "max_cpu_speed"); validateMinMaxIntValues(param.getMinMemory(), param.getMaxMemory(), "min_memory", "max_memory"); validateMinMaxIntValues(param.getMinNics(), param.getMaxNics(), "min_nics", "max_nics"); validateMinMaxIntValues(param.getMinHbas(), param.getMaxHbas(), "min_hbas", "max_hbas"); // Create Compute Virtual Pool ComputeVirtualPool cvp = new ComputeVirtualPool(); // Populate Virtual Pool if(NullColumnValueGetter.isNotNullValue(param.getId())) { cvp.setId(URI.create(param.getId())); } else { cvp.setId(URIUtil.createId(ComputeVirtualPool.class)); } cvp.setLabel(param.getName()); cvp.setDescription(param.getDescription()); cvp.setSystemType(param.getSystemType()); cvp.setMinProcessors(param.getMinProcessors()); cvp.setMaxProcessors(param.getMaxProcessors()); cvp.setMinTotalCores(param.getMinTotalCores()); cvp.setMaxTotalCores(param.getMaxTotalCores()); cvp.setMinTotalThreads(param.getMinTotalThreads()); cvp.setMaxTotalThreads(param.getMaxTotalThreads()); cvp.setMinCpuSpeed(param.getMinCpuSpeed()); cvp.setMaxCpuSpeed(param.getMaxCpuSpeed()); cvp.setMinMemory(param.getMinMemory()); cvp.setMaxMemory(param.getMaxMemory()); cvp.setMinNics(param.getMinNics()); cvp.setMaxNics(param.getMaxNics()); cvp.setMinHbas(param.getMinHbas()); cvp.setMaxHbas(param.getMaxHbas()); // Validate and set Virtual Arrays Set<String> addVarrays = param.getVarrays(); if (addVarrays != null && !addVarrays.isEmpty()) { cvp.setVirtualArrays(new StringSet()); for (String vArray : addVarrays) { URI vArrayURI = URI.create(vArray); ArgValidator.checkUri(vArrayURI); this.queryObject(VirtualArray.class, vArrayURI, true); cvp.getVirtualArrays().add(vArray); } } cvp.setUseMatchedElements(param.getUseMatchedElements()); validateAndSetSpts(cvp, param.getServiceProfileTemplates()); if (cvp.getUseMatchedElements()) { _log.debug("Compute pool " + cvp.getLabel() + " configured to use dynamic matching"); getMatchingCEsforCVPAttributes(cvp); } return cvp; } private ComputeElementListRestRep extractComputeElements(ComputeVirtualPool cvp) { ComputeElementListRestRep result = new ComputeElementListRestRep(); if (cvp.getMatchedComputeElements() != null) { Collection<ComputeElement> computeElements = _dbClient.queryObject(ComputeElement.class, toUriList(cvp.getMatchedComputeElements())); Collection<URI> hostIds = _dbClient.queryByType(Host.class, true); Collection<Host> hosts = _dbClient.queryObjectFields(Host.class, Arrays.asList("label", "computeElement", "cluster"), ControllerUtils.getFullyImplementedCollection(hostIds)); for (ComputeElement computeElement : computeElements) { if (computeElement!=null) { Host associatedHost = null; for (Host host : hosts){ if (!NullColumnValueGetter.isNullURI(host.getComputeElement()) && host.getComputeElement().equals(computeElement.getId())) { associatedHost = host; break; } } Cluster cluster = null; if (associatedHost!=null && !NullColumnValueGetter.isNullURI(associatedHost.getCluster())){ cluster = _dbClient.queryObject(Cluster.class, associatedHost.getCluster()); } ComputeElementRestRep rest = map(computeElement, associatedHost, cluster); result.getList().add(rest); } } } return result; } /** * Get compute elements that match the Compute Virtual Pool criteria * * @brief Get compute elements that match the Compute Virtual Pool criteria * @param param The Compute Virtual Pool create spec containing the criteria * @return ComputeElementListRestRep collection of Compute Elements */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) @Path("/matching-compute-elements") public ComputeElementListRestRep getMatchingComputeElements(ComputeVirtualPoolCreateParam param) throws DatabaseException { ComputeVirtualPool cvp = constructAndValidateComputeVirtualPool(param); return extractComputeElements(cvp); } /** * Create a Compute Virtual Pool * * @brief Create a compute virtual pool * @param param The Compute Virtual Pool create spec * @return ComputeVirtualPoolRestRep The created Compute Virtual Pool */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public ComputeVirtualPoolRestRep createComputeVirtualPool(ComputeVirtualPoolCreateParam param) throws DatabaseException { checkForDuplicateName(param.getName(), ComputeVirtualPool.class); ComputeVirtualPool cvp = constructAndValidateComputeVirtualPool(param); _dbClient.createObject(cvp); updateHostToCVPRelation(cvp); recordOperation(OperationTypeEnum.CREATE_COMPUTE_VPOOL, VPOOL_CREATED_DESCRIPTION, cvp); return toComputeVirtualPool(_dbClient, cvp, isComputeVirtualPoolInUse(cvp)); } private List<URI> getURIs(Collection<ComputeElement> elements) throws APIException { List<URI> uriList = new ArrayList<URI>(); if (elements == null || elements.isEmpty()) { return uriList; } for (ComputeElement element : elements) { URI uri = element.getId(); uriList.add(uri); } return uriList; } private void validateAndSetSpts(ComputeVirtualPool cvp, Set<String> addSpts) { _log.debug("System type = " + cvp.getSystemType()); if (cvp.getSystemType().contentEquals(ComputeVirtualPool.SupportedSystemTypes.Cisco_UCSM.toString())) { // Process Service Profile Templates _log.debug("Processing Service Profile Templates"); if (addSpts != null && !addSpts.isEmpty()) { _log.debug("Found SPTs to add"); for (String spt : addSpts) { URI sptURI = URI.create(spt); ArgValidator.checkUri(sptURI); this.queryObject(UCSServiceProfileTemplate.class, sptURI, true); } // Initialize set of compute systems used Set<URI> sptComputeSystems = new HashSet<URI>(); cvp.setServiceProfileTemplates(new StringSet()); // Iterate over all SPTs in returned in the param stringset Collection<UCSServiceProfileTemplate> templates = _dbClient .queryObject(UCSServiceProfileTemplate.class, toUriList(addSpts)); if (addSpts.size() != templates.size()) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Invalid service profile template specified."); } for (UCSServiceProfileTemplate template : templates) { _log.debug("Adding SPT : " + template.getId().toString()); // verify the SPT exists in the db ArgValidator.checkEntity(template, template.getId(), isIdEmbeddedInURL(template.getId())); // verify that there was not already an SPT with the same compute system (check set) if (sptComputeSystems.contains(template.getComputeSystem())) { throw APIException.badRequests .changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Duplicate assignment of service profile template for compute system. Only one service profile template per compute system is permitted."); } // verify the number of nic and hbas match the associated ranges (if set) if (cvp.getMinNics() != null) { ArgValidator.checkFieldMinimum(template.getNumberOfVNICS(), cvp.getMinNics(), "service_profile_template"); } if (cvp.getMaxNics() != null && (cvp.getMaxNics() != -1)) { ArgValidator.checkFieldMaximum(template.getNumberOfVNICS(), cvp.getMaxNics(), "service_profile_template"); } if (cvp.getMinHbas() != null) { ArgValidator.checkFieldMinimum(template.getNumberOfVHBAS(), cvp.getMinHbas(), "service_profile_template"); } if (cvp.getMaxHbas() != null && (cvp.getMaxHbas() != -1)) { ArgValidator.checkFieldMaximum(template.getNumberOfVHBAS(), cvp.getMaxHbas(), "service_profile_template"); } if (template.getUpdating() == true) { if (!computeSystemService.isUpdatingSPTValid(template, _dbClient)) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Nic or hba names in updating service profile template " + template.getLabel() + " do not match those in its boot policy."); } } if (!computeSystemService.isServiceProfileTemplateValidForVarrays(cvp.getVirtualArrays(), template.getId())) { throw APIException.badRequests.sptIsNotValidForVarrays(template.getLabel()); } // add the spt to the VCP cvp.getServiceProfileTemplates().add(template.getId().toString()); // update the set of compute systems used sptComputeSystems.add(template.getComputeSystem()); } } } } private List<URI> findAllStaticallyAssignedComputeElements() { Collection<String> staticallyAssignedComputeElementUriStrings = new HashSet<String>(); List<URI> computeVirtualPoolUris = _dbClient.queryByType(ComputeVirtualPool.class, true); Collection<ComputeVirtualPool> computeVirtualPools = _dbClient.queryObject(ComputeVirtualPool.class, computeVirtualPoolUris); for (ComputeVirtualPool computeVirtualPool : computeVirtualPools) { if (!computeVirtualPool.getUseMatchedElements()) { _log.debug("Compute pool " + computeVirtualPool.getLabel() + " using static matching"); if (computeVirtualPool.getMatchedComputeElements() != null) { _log.debug("Compute pool " + computeVirtualPool.getLabel() + " has " + computeVirtualPool.getMatchedComputeElements().size() + " statically assigned compute elements"); staticallyAssignedComputeElementUriStrings.addAll(computeVirtualPool.getMatchedComputeElements()); } } } _log.debug("Found " + computeVirtualPools.size() + " compute pools using static matching containing the following compute elements: " + staticallyAssignedComputeElementUriStrings); return toUriList(staticallyAssignedComputeElementUriStrings); } private List<URI> findAllStaticallyAssignedComputeElementsInOtherPools(ComputeVirtualPool computeVirtualPool) { List<URI> staticallyAssignedComputeElements = findAllStaticallyAssignedComputeElements(); //fetch cvp from db ComputeVirtualPool cvp = _dbClient.queryObject(ComputeVirtualPool.class, computeVirtualPool.getId()); List<URI> poolUris = Lists.newArrayList(); if(null != cvp) { poolUris = toUriList(cvp.getMatchedComputeElements()); } else { poolUris = toUriList(computeVirtualPool.getMatchedComputeElements()); } if (!poolUris.isEmpty() && !staticallyAssignedComputeElements.isEmpty()) { _log.debug("Remove " + poolUris.size() + " previously assigned compute elements from list of " + staticallyAssignedComputeElements.size() + " static elements"); for (URI computeElementId : poolUris) { boolean removed = staticallyAssignedComputeElements.remove(computeElementId); if (removed) { _log.debug("Compute element " + computeElementId + " from pool " + computeVirtualPool.getId() + " removed from staticallyAssignedComputeElements"); } } } return staticallyAssignedComputeElements; } private List<URI> findComputeElementsFromDeviceAssociations(ComputeVirtualPool computeVirtualPool) { // Get CEs from associated varrays List<URI> ceList = new ArrayList<URI>(); if (computeVirtualPool.getVirtualArrays() != null) { for (String virtualArrayId : computeVirtualPool.getVirtualArrays()) { URI virtualArrayURI = URI.create(virtualArrayId); ArgValidator.checkUri(virtualArrayURI); this.queryObject(VirtualArray.class, virtualArrayURI, true); _log.debug("Look up compute systems for virtual array " + virtualArrayURI); ComputeSystemBulkRep computeSystemBulkRep = virtualArrayService.getComputeSystems(virtualArrayURI); if (computeSystemBulkRep.getComputeSystems() != null) { for (ComputeSystemRestRep computeSystemRestRep : computeSystemBulkRep.getComputeSystems()) { _log.debug("Found compute system " + computeSystemRestRep.getId() + " for virtual array " + virtualArrayURI); ComputeElementListRestRep computeElementListRestRep = computeSystemService.getComputeElements(computeSystemRestRep .getId()); if (computeElementListRestRep.getList() != null) { for (ComputeElementRestRep computeElementRestRep : computeElementListRestRep.getList()) { _log.debug("Compute system contains compute element " + computeElementRestRep.getId()); ceList.add(computeElementRestRep.getId()); } } } } } } return ceList; } private boolean isRegistered(ComputeElement computeElement) { return RegistrationStatus.REGISTERED.name().equals(computeElement.getRegistrationStatus()); } private boolean isAvailable(ComputeElement computeElement) { return RegistrationStatus.REGISTERED.name().equals(computeElement.getRegistrationStatus()) && computeElement.getAvailable(); } public void getMatchingCEsforCVPAttributes(ComputeVirtualPool cvp) { // TODO : first iterate over Compute Systems and find ones with association to the vArrays // New search function to be added to the Compute Systems to search for associated vArrays if (cvp.getMatchedComputeElements() != null) { cvp.getMatchedComputeElements().clear(); } String sysType = null; if (cvp.getSystemType() != null) { if (cvp.getSystemType().contentEquals(ComputeVirtualPool.SupportedSystemTypes.Cisco_UCSM.toString())) { sysType = "ucs"; } } if (sysType != null) { _log.debug("Iterating over all CEs"); List<URI> ceList = findComputeElementsFromDeviceAssociations(cvp); List<URI> staticallyAssignedComputeElements = findAllStaticallyAssignedComputeElementsInOtherPools(cvp); StringSet ceIds = new StringSet(); Collection<ComputeElement> computeElements = _dbClient.queryObject(ComputeElement.class, ceList); for (ComputeElement ce : computeElements) { if (ce.getSystemType() == null) { continue; } if (!ce.getSystemType().contentEquals((CharSequence) sysType)) { continue; } if (!isRegistered(ce)) { continue; } if (staticallyAssignedComputeElements.contains(ce.getId())) { _log.debug("Compute element " + ce.getId() + " has been statically assigned and will be filtered out"); continue; } if (isParamSet(cvp.getMinTotalCores()) && (ce.getNumOfCores() < cvp.getMinTotalCores())) { continue; } if (isParamSet(cvp.getMaxTotalCores()) && (cvp.getMaxTotalCores() != -1) && (ce.getNumOfCores() > cvp.getMaxTotalCores())) { continue; } if (isParamSet(cvp.getMinProcessors()) && (ce.getNumberOfProcessors() < cvp.getMinProcessors())) { continue; } if (isParamSet(cvp.getMaxProcessors()) && (cvp.getMaxProcessors() != -1) && (ce.getNumberOfProcessors() > cvp.getMaxProcessors())) { continue; } if (isParamSet(cvp.getMinTotalThreads()) && (ce.getNumberOfThreads() < cvp.getMinTotalThreads())) { continue; } if (isParamSet(cvp.getMaxTotalThreads()) && (cvp.getMaxTotalThreads() != -1) && (ce.getNumberOfThreads() > cvp.getMaxTotalThreads())) { continue; } float ceSpeed = Float.parseFloat(ce.getProcessorSpeed()); if (isParamSet(cvp.getMinCpuSpeed())) { if (ceSpeed < (float) cvp.getMinCpuSpeed()) { continue; } } if (isParamSet(cvp.getMaxCpuSpeed()) && (cvp.getMaxCpuSpeed() != -1)) { if (ceSpeed > (float) cvp.getMaxCpuSpeed()) { continue; } } if (isParamSet(cvp.getMinMemory()) && (ce.getRam() / 1024 < cvp.getMinMemory())) { continue; } if (isParamSet(cvp.getMaxMemory()) && (cvp.getMaxMemory() != -1) && (ce.getRam() / 1024 > cvp.getMaxMemory())) { continue; } ceIds.add(ce.getId().toASCIIString()); } cvp.addMatchedComputeElements(ceIds); Integer size = cvp.getMatchedComputeElements() != null ? cvp.getMatchedComputeElements().size() : 0; _log.debug("putting CEs in the pool, cnt: " + size); } } private boolean isParamSet(Integer param) { return param != null && param != 0; } private Integer getParamValue(Integer param) { return isParamSet(param) ? param : 0; } private Integer getParamMaxValue(Integer param) { return isParamSet(param) ? param : -1; } /** * Update a Compute Virtual Pool * * @brief Update a compute virtual pool * @param param The Compute Virtual Pool update spec * @return ComputeVirtualPoolRestRep The updated Compute Virtual Pool */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public ComputeVirtualPoolRestRep updateComputeVirtualPool(@PathParam("id") URI id, ComputeVirtualPoolUpdateParam param) { ComputeVirtualPool cvp = null; _log.debug("Update Parameters:\n" + param.toString()); // Validate that Virtual Pool exists ArgValidator.checkFieldUriType(id, ComputeVirtualPool.class, "id"); cvp = this.queryObject(ComputeVirtualPool.class, id, true); boolean nicOrHbaRangeChanges = false; boolean moreRestrictiveChange = false; // If current value not set OR if param is more restrictive then change is more restrictive // Process the update parameters // If a name is specified on request and that value is different that current name boolean nameChange = (param.getName() != null && !(cvp.getLabel().equals(param.getName()))); if (nameChange) { checkForDuplicateName(param.getName(), ComputeVirtualPool.class); cvp.setLabel(param.getName()); } if (null != param.getDescription()) { cvp.setDescription(param.getDescription()); } if (null != param.getSystemType()) { ArgValidator.checkFieldValueFromEnum(param.getSystemType(), "system_type", ComputeVirtualPool.SupportedSystemTypes.class); // Don't allow changes of system type if there are service profile templates already set if (cvp.getServiceProfileTemplates() != null) { if (!cvp.getServiceProfileTemplates().isEmpty()) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot change system type when Service Profile Temples are associated"); } } cvp.setSystemType(param.getSystemType()); } if (isParamSet(param.getMinProcessors()) && ((cvp.getMinProcessors() == null) || (cvp.getMinProcessors() < param.getMinProcessors()))) { moreRestrictiveChange = true; _log.debug("Min Processors increased from " + cvp.getMinProcessors() + " to " + param.getMinProcessors()); } cvp.setMinProcessors(getParamValue(param.getMinProcessors())); if (isParamSet(param.getMaxProcessors()) && ((cvp.getMaxProcessors() == null) || (cvp.getMaxProcessors() == -1) || (cvp.getMaxProcessors() > param .getMaxProcessors()))) { moreRestrictiveChange = true; _log.debug("Max Processors decreased from " + cvp.getMaxProcessors() + " to " + param.getMaxProcessors()); } cvp.setMaxProcessors(getParamMaxValue(param.getMaxProcessors())); validateMinMaxIntValues(cvp.getMinProcessors(), cvp.getMaxProcessors(), "min_processors", "max_processors"); if (isParamSet(param.getMinTotalCores()) && ((cvp.getMinTotalCores() == null) || (cvp.getMinTotalCores() < param.getMinTotalCores()))) { moreRestrictiveChange = true; _log.debug("Min TotalCores increased from " + cvp.getMinTotalCores() + " to " + param.getMinTotalCores()); } cvp.setMinTotalCores(getParamValue(param.getMinTotalCores())); if (isParamSet(param.getMaxTotalCores()) && ((cvp.getMaxTotalCores() == null) || (cvp.getMaxTotalCores() == -1) || (cvp.getMaxTotalCores() > param .getMaxTotalCores()))) { moreRestrictiveChange = true; _log.debug("Max TotalCores decreased from " + cvp.getMaxTotalCores() + " to " + param.getMaxTotalCores()); } cvp.setMaxTotalCores(getParamMaxValue(param.getMaxTotalCores())); validateMinMaxIntValues(cvp.getMinTotalCores(), cvp.getMaxTotalCores(), "min_total_cores", "max_total_cores"); if (isParamSet(param.getMinTotalThreads()) && ((cvp.getMinTotalThreads() == null) || (cvp.getMinTotalThreads() < param.getMinTotalThreads()))) { moreRestrictiveChange = true; _log.debug("Min TotalThreads increased from " + cvp.getMinTotalThreads() + " to " + param.getMinTotalThreads()); } cvp.setMinTotalThreads(getParamValue(param.getMinTotalThreads())); if (isParamSet(param.getMaxTotalThreads()) && ((cvp.getMaxTotalThreads() == null) || (cvp.getMaxTotalThreads() == -1) || (cvp.getMaxTotalThreads() > param .getMaxTotalThreads()))) { moreRestrictiveChange = true; _log.debug("Max TotalThreads decreased from " + cvp.getMaxTotalThreads() + " to " + param.getMaxMemory()); } cvp.setMaxTotalThreads(getParamMaxValue(param.getMaxTotalThreads())); validateMinMaxIntValues(cvp.getMinTotalThreads(), cvp.getMaxTotalThreads(), "min_total_threads", "max_total_threads"); if (isParamSet(param.getMinCpuSpeed()) && ((cvp.getMinCpuSpeed() == null) || (cvp.getMinCpuSpeed() < param.getMinCpuSpeed()))) { moreRestrictiveChange = true; _log.debug("Min CpuSpeed increased from " + cvp.getMinCpuSpeed() + " to " + param.getMinCpuSpeed()); } cvp.setMinCpuSpeed(getParamValue(param.getMinCpuSpeed())); if (isParamSet(param.getMaxCpuSpeed()) && ((cvp.getMaxCpuSpeed() == null) || (cvp.getMaxCpuSpeed() == -1) || (cvp.getMaxCpuSpeed() > param.getMaxCpuSpeed()))) { moreRestrictiveChange = true; _log.debug("Max CpuSpeed decreased from " + cvp.getMaxCpuSpeed() + " to " + param.getMaxCpuSpeed()); } cvp.setMaxCpuSpeed(getParamMaxValue(param.getMaxCpuSpeed())); validateMinMaxIntValues(cvp.getMinCpuSpeed(), cvp.getMaxCpuSpeed(), "min_processor_speed", "max_processor_speed"); if (isParamSet(param.getMinMemory()) && ((cvp.getMinMemory() == null) || (cvp.getMinMemory() < param.getMinMemory()))) { moreRestrictiveChange = true; _log.debug("Min Memory increased from " + cvp.getMinMemory() + " to " + param.getMinMemory()); } cvp.setMinMemory(getParamValue(param.getMinMemory())); if (isParamSet(param.getMaxMemory()) && ((cvp.getMaxMemory() == null) || (cvp.getMaxMemory() == -1) || (cvp.getMaxMemory() > param.getMaxMemory()))) { moreRestrictiveChange = true; _log.debug("Max Memory decreased from " + cvp.getMaxMemory() + " to " + param.getMaxMemory()); } cvp.setMaxMemory(getParamMaxValue(param.getMaxMemory())); validateMinMaxIntValues(cvp.getMinMemory(), cvp.getMaxMemory(), "min_memory", "max_memory"); boolean moreRestrictiveNicHbaChange = false; // If current value not set OR if param is more restrictive then change is more // restrictive if (isParamSet(param.getMinNics()) && ((cvp.getMinNics() == null) || (cvp.getMinNics() < param.getMinNics()))) { moreRestrictiveNicHbaChange = true; _log.debug("Min nic increased from " + cvp.getMinNics() + " to " + param.getMinNics()); } cvp.setMinNics(getParamValue(param.getMinNics())); if (isParamSet(param.getMaxNics()) && ((cvp.getMaxNics() == null) || (cvp.getMaxNics() == -1) || (cvp.getMaxNics() > param.getMaxNics()))) { moreRestrictiveNicHbaChange = true; _log.debug("Max nic decreased from " + cvp.getMaxNics() + " to " + param.getMaxNics()); } cvp.setMaxNics(getParamMaxValue(param.getMaxNics())); validateMinMaxIntValues(cvp.getMinNics(), cvp.getMaxNics(), "min_nics", "max_nics"); if (isParamSet(param.getMinHbas()) && ((cvp.getMinHbas() == null) || (cvp.getMinHbas() < param.getMinHbas()))) { moreRestrictiveNicHbaChange = true; _log.debug("Min hba increased from " + cvp.getMinHbas() + " to " + param.getMinHbas()); } cvp.setMinHbas(getParamValue(param.getMinHbas())); if (isParamSet(param.getMaxHbas()) && ((cvp.getMaxHbas() == null) || (cvp.getMaxHbas() == -1) || (cvp.getMaxHbas() > param.getMaxHbas()))) { moreRestrictiveNicHbaChange = true; _log.debug("Max hba decreased from " + cvp.getMaxHbas() + " to " + param.getMaxHbas()); } cvp.setMaxHbas(getParamMaxValue(param.getMaxHbas())); validateMinMaxIntValues(cvp.getMinHbas(), cvp.getMaxHbas(), "min_hbas", "max_hbas"); boolean changeToStaticAssignment = false; boolean changeToDynamicAssignment = false; Collection<ComputeElement> staticElements = new HashSet<ComputeElement>(); if (!cvp.getUseMatchedElements() && cvp.getMatchedComputeElements() != null && !cvp.getMatchedComputeElements().isEmpty()) { staticElements.addAll(_dbClient.queryObject(ComputeElement.class, toUriList(cvp.getMatchedComputeElements()))); _log.debug("static elements count:" + staticElements.size()); } if (null != param.getUseMatchedElements()) { // Will need to clear current matches when changing to static assignment changeToStaticAssignment = (param.getUseMatchedElements() == false) && (param.getUseMatchedElements() != cvp.getUseMatchedElements()); changeToDynamicAssignment = (param.getUseMatchedElements() == true) && (param.getUseMatchedElements() != cvp.getUseMatchedElements()); cvp.setUseMatchedElements(param.getUseMatchedElements()); } if (changeToStaticAssignment) { // Clear dynamic matches when changing to static to get ready for upcoming assignments if (cvp.getMatchedComputeElements() != null) { cvp.getMatchedComputeElements().clear(); } } if (null != param.getVarrayChanges()) { updateVirtualArrays(cvp, param.getVarrayChanges()); } if (null != param.getSptChanges()) { if (cvp.getSystemType().contentEquals(ComputeVirtualPool.SupportedSystemTypes.Cisco_UCSM.toString())) { updateServiceProfileTemplates(cvp, param.getSptChanges()); } } // Check SPTs meet criteria after updates above if (moreRestrictiveNicHbaChange) { if (isComputeVirtualPoolInUse(cvp)) { _log.warn("VCP is in use; more restrictive Nic or Hba change is not allowed"); throw APIException.badRequests .changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "More restrictive updates to network adapter and hba range not allowed because compute virtual pool is already in use."); } Set<String> sptsNotMeetingCriteria = new HashSet<String>(); Collection<UCSServiceProfileTemplate> templates = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(cvp.getServiceProfileTemplates())); for (UCSServiceProfileTemplate template : templates) { boolean inUse = isServiceProfileTemplateInUse(cvp, template); try { validateServiceProfileTemplate(cvp, template); } catch (APIException e) { _log.warn("SPT " + template.getLabel() + ":" + template.getDn() + " is in use(" + inUse + ") and does not meet criteria " + e.toString()); /* * Since we are disallowing more restrictive changes if the VCP is in use, the if block below will not be used for the * 2.2 release. */ if (inUse) { throw APIException.badRequests .changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Updates to pool not allowed because service profile template(s) already in use do not meet requested criteria."); } sptsNotMeetingCriteria.add(template.getId().toString()); // if spt not in use then simply remove _log.warn("SPT does not meet criteria; so being removed"); } } cvp.removeServiceProfileTemplates(sptsNotMeetingCriteria); } if (cvp.getUseMatchedElements()) { _log.debug("Compute pool " + cvp.getLabel() + " configured to use dynamic matching"); getMatchingCEsforCVPAttributes(cvp); } if (changeToDynamicAssignment && !staticElements.isEmpty()) { // Release static assignments and update other pools dynamic matches // to possibly include them for (ComputeElement computeElement : staticElements) { if (!isAvailable(computeElement)) { _log.error("Cannot change to dynamic matching because statically assigned compute element(s) have been used in pool " + cvp.getId()); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot change to automatic matching because manually assigned compute element(s) already in use."); } } updateOtherPoolsComputeElements(cvp); } if (moreRestrictiveChange) { if (isComputeVirtualPoolInUse(cvp)) { _log.warn("VCP is in use; more restrictive change is not allowed"); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "More restrictive updates to qualifiers not allowed because compute virtual pool is already in use."); } // VCP is not in use. So check if there are statically assigned members that need to be removed from vcp membership _log.info("VCP is not in use. So check if there are statically assigned members that need to be removed from vcp membership"); if (!cvp.getUseMatchedElements() && !staticElements.isEmpty()) { Set<ComputeElement> cesNotMeetingCriteria = new HashSet<ComputeElement>(); Collection<ComputeElement> computeElements = _dbClient.queryObject(ComputeElement.class, getURIs(staticElements)); for (ComputeElement element : computeElements) { _log.debug("Blade:" + element.getChassisId() + "/" + element.getSlotId()); boolean inUse = (element.getAvailable() == false); try { validateComputeElement(cvp, element); } catch (APIException e) { _log.warn("Compute Element " + element.getLabel() + ":" + element.getDn() + " is in use(" + inUse + ") and does not meet criteria " + e.toString()); /* * Since we are disallowing more restrictive changes if the VCP is in use, the if block below will not be used for * the 2.2 release. */ if (inUse) { throw APIException.badRequests .changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Updates to pool not allowed because compute element(s) already in use do not meet requested criteria."); } cesNotMeetingCriteria.add(element); // if ces not in use then simply remove _log.warn("Compute Element does not meet criteria; so being removed"); } } } } updateHostToCVPRelation(cvp); _dbClient.updateAndReindexObject(cvp); recordOperation(OperationTypeEnum.UPDATE_COMPUTE_VPOOL, VPOOL_UPDATED_DESCRIPTION, cvp); return toComputeVirtualPool(_dbClient, cvp, isComputeVirtualPoolInUse(cvp)); } /** * Updates the virtual arrays to which the compute virtual pool is assigned. * * @param cvp - A reference to the compute virtual pool. * * @return true if there was a virtual array assignment change, false otherwise. */ private boolean updateVirtualArrays(ComputeVirtualPool cvp, VirtualArrayAssignmentChanges varrayAssignmentChanges) { // Validate that the Virtual Arrays to be assigned to the Compute Virtual Pool // reference existing Virtual Arrays in the database and add them to // to the CVP. boolean varraysForCvpUpdated = false; Set<String> varraysAddedToCvp = new HashSet<String>(); Set<String> varraysRemovedFromCvp = new HashSet<String>(); if (varrayAssignmentChanges != null) { _log.debug("Update request has virtual array assignment changes for compute virtual pool {}", cvp.getId()); // Verify the assignment changes in the request. verifyAssignmentChanges(cvp, varrayAssignmentChanges); _log.debug("Requested virtual array assignment changes verified."); VirtualArrayAssignments addAssignments = varrayAssignmentChanges.getAdd(); if (addAssignments != null) { Set<String> addVArrays = addAssignments.getVarrays(); if ((addVArrays != null) && (!addVArrays.isEmpty())) { _log.debug("Request specifies virtual arrays to be added."); // Validate the requested URIs. VirtualArrayService.checkVirtualArrayURIs(addVArrays, _dbClient); // Iterate over the virtual arrays and assign them to the CVP. StringSet currentAssignments = cvp.getVirtualArrays(); Iterator<String> addVArraysIter = addVArrays.iterator(); while (addVArraysIter.hasNext()) { String addVArrayId = addVArraysIter.next(); if ((currentAssignments != null) && (currentAssignments.contains(addVArrayId))) { // Just ignore those already assigned _log.debug("Compute Virtual Pool already assigned to virtual array {}", addVArrayId); continue; } // Verify that the Virtual Array is active URI virtualArrayURI = null; virtualArrayURI = URI.create(addVArrayId); this.queryObject(VirtualArray.class, virtualArrayURI, true); varraysAddedToCvp.add(addVArrayId); varraysForCvpUpdated = true; _log.debug("Compute Virtual Pool will be assigned to virtual array {}", addVArrayId); } } } // Validate that the Virtual Arrays to be unassigned from the // Compute Virtual Pool reference existing Virtual Arrays in the database // and remove them from the CVP. VirtualArrayAssignments removeAssignments = varrayAssignmentChanges.getRemove(); if (removeAssignments != null) { Set<String> removeVArrays = removeAssignments.getVarrays(); // If the vcp is in use, varrays cannot be removed from the vcp. if (isComputeVirtualPoolInUse(cvp)) { throw APIException.badRequests.cannotRemoveVarraysFromCVP(cvp.getLabel()); } if ((removeVArrays != null) && (!removeVArrays.isEmpty())) { _log.debug("Request specifies virtual arrays to be removed."); // Iterate over the virtual arrays and unassign from the CVP StringSet currentAssignments = cvp.getVirtualArrays(); Iterator<String> removeVArraysIter = removeVArrays.iterator(); while (removeVArraysIter.hasNext()) { String removeVArrayId = removeVArraysIter.next(); if ((currentAssignments == null) || (!currentAssignments.contains(removeVArrayId))) { // Just ignore those not assigned. _log.debug("Compute Virtual Pool is not assigned to virtual array {}", removeVArrayId); continue; } varraysRemovedFromCvp.add(removeVArrayId); varraysForCvpUpdated = true; _log.debug("Compute Virtual Pool will be unassigned from virtual array {}", removeVArrayId); } } } } // Persist virtual array changes for the Compute Virtual Pool, if any. if (varraysForCvpUpdated) { if (!varraysAddedToCvp.isEmpty()) { cvp.addVirtualArrays(varraysAddedToCvp); } if (!varraysRemovedFromCvp.isEmpty()) { cvp.removeVirtualArrays(varraysRemovedFromCvp); } } return varraysForCvpUpdated; } /** * Verifies the virtual array assignment changes in the update request are * valid, else throws a bad request exception. * * @param cvp - A reference to a Compute Virtual Pool. * @param varrayAssignmentChanges The virtual array assignment changes in a * compute virtual pool update request. */ private void verifyAssignmentChanges(ComputeVirtualPool cvp, VirtualArrayAssignmentChanges varrayAssignmentChanges) { // Verify the add/remove sets do not overlap. VirtualArrayAssignments addAssignments = varrayAssignmentChanges.getAdd(); VirtualArrayAssignments removeAssignments = varrayAssignmentChanges.getRemove(); if ((addAssignments != null) && (removeAssignments != null)) { Set<String> addVArrays = addAssignments.getVarrays(); Set<String> removeVArrays = removeAssignments.getVarrays(); if ((addVArrays != null) && (removeVArrays != null)) { Set<String> addSet = new HashSet<String>(addVArrays); Set<String> removeSet = new HashSet<String>(removeVArrays); addSet.retainAll(removeSet); if (!addSet.isEmpty()) { _log.error("Request specifies the same virtual array(s) in both the add and remove lists {}", addSet); throw APIException.badRequests.sameVirtualArrayInAddRemoveList(); } } } } public boolean isComputeVirtualPoolInUse(ComputeVirtualPool cvp) { boolean inUse = false; _log.debug("Checking if vcp is in use: " + inUse); if (cvp.getId() != null) { List<Host> hosts = getHostsProvisionedFromPool(cvp); if (hosts != null && !hosts.isEmpty()) { inUse = true; } } return inUse; } /* * TODO - Implement with logic to determine if SPT is provisioned or in use * Remove cvp from method signature since its just there for mock testing * But shouldn't this method say whether the SPT has been used to provision a host from this vcp? */ public boolean isServiceProfileTemplateInUse(ComputeVirtualPool cvp, UCSServiceProfileTemplate ucsServiceProfileTemplate) { _log.debug("Check if SPT " + ucsServiceProfileTemplate.getDn() + " is in use"); if (cvp.getDescription() != null && cvp.getDescription().contains("provisioned")) { return true; } else { return false; } } private void validateServiceProfileTemplate(ComputeVirtualPool cvp, UCSServiceProfileTemplate template) throws APIException { // verify the number of nic and hbas match the associated ranges (if set) if (cvp.getMinNics() != null) { ArgValidator.checkFieldMinimum(template.getNumberOfVNICS(), cvp.getMinNics(), "service_profile_template number of nics"); } if (cvp.getMaxNics() != null && (cvp.getMaxNics() != -1)) { ArgValidator.checkFieldMaximum(template.getNumberOfVNICS(), cvp.getMaxNics(), "service_profile_template number of nics"); } if (cvp.getMinHbas() != null) { ArgValidator.checkFieldMinimum(template.getNumberOfVHBAS(), cvp.getMinHbas(), "service_profile_template number of hbas"); } if (cvp.getMaxHbas() != null && (cvp.getMaxHbas() != -1)) { ArgValidator.checkFieldMaximum(template.getNumberOfVHBAS(), cvp.getMaxHbas(), "service_profile_template number of hbas"); } } private void validateComputeElement(ComputeVirtualPool cvp, ComputeElement ce) { _log.debug("in validateComputeElement"); if (isParamSet(cvp.getMinProcessors())) { ArgValidator.checkFieldMinimum(ce.getNumberOfProcessors(), cvp.getMinProcessors(), "compute element number of processors"); } if (isParamSet(cvp.getMaxProcessors()) && (cvp.getMaxProcessors() != -1)) { ArgValidator.checkFieldMaximum(ce.getNumberOfProcessors(), cvp.getMaxProcessors(), "compute element number of processors"); } if (ce.getProcessorSpeed() != null) { try { float processorSpeed = Float.parseFloat(ce.getProcessorSpeed()); if (isParamSet(cvp.getMinCpuSpeed())) { if (processorSpeed < cvp.getMinCpuSpeed()) { throw APIException.badRequests.invalidFloatParameterBelowMinimum("compute element processor speed", processorSpeed, cvp.getMinCpuSpeed(), " "); } } if (isParamSet(cvp.getMaxCpuSpeed()) && (cvp.getMaxCpuSpeed() != -1)) { if (processorSpeed > cvp.getMaxCpuSpeed()) { throw APIException.badRequests.invalidFloatParameterAboveMaximum("compute element processor speed", processorSpeed, cvp.getMaxCpuSpeed(), " "); } } } catch (NumberFormatException e) { // processorSpeed not specified. ignore } } if (isParamSet(cvp.getMinMemory())) { ArgValidator.checkFieldMinimum(ce.getRam(), cvp.getMinMemory() * 1024, "compute element memory"); } if (isParamSet(cvp.getMaxMemory()) && (cvp.getMaxMemory() != -1)) { ArgValidator.checkFieldMaximum(ce.getRam(), cvp.getMaxMemory() * 1024, "compute element memory"); } if (isParamSet(cvp.getMinTotalCores())) { ArgValidator.checkFieldMinimum(ce.getNumOfCores(), cvp.getMinTotalCores(), "compute element total cores"); } if (isParamSet(cvp.getMaxTotalCores()) && (cvp.getMaxTotalCores() != -1)) { ArgValidator.checkFieldMaximum(ce.getNumOfCores(), cvp.getMaxTotalCores(), "compute element total cores"); } if (isParamSet(cvp.getMinTotalThreads())) { ArgValidator.checkFieldMinimum(ce.getNumberOfThreads(), cvp.getMinTotalThreads(), "compute element total threads"); } if (isParamSet(cvp.getMaxTotalThreads()) && (cvp.getMaxTotalThreads() != -1)) { ArgValidator.checkFieldMaximum(ce.getNumberOfThreads(), cvp.getMaxTotalThreads(), "compute element total threads"); } } /** * Updates the service profile templates to which the compute virtual pool is assigned. * * @param cvp - A reference to the compute virtual pool. * * @return true if there was a service profile template assignment change, false otherwise. */ private boolean updateServiceProfileTemplates(ComputeVirtualPool cvp, ServiceProfileTemplateAssignmentChanges sptAssignmentChanges) { // Validate that the SPTs to be assigned to the Compute Virtual Pool // reference existing SPTs in the database and add them to // to the CVP. boolean sptsForCvpUpdated = false; Set<String> sptsAddedToCvp = new HashSet<String>(); Set<String> sptsRemovedFromCvp = new HashSet<String>(); if (sptAssignmentChanges != null) { _log.debug("Update request has service profile template assignment changes for compute virtual pool {}", cvp.getId()); // Verify the assignment changes in the request. verifySptAssignmentChanges(cvp, sptAssignmentChanges); _log.debug("Requested service profile template assignment changes verified."); ServiceProfileTemplateAssignments addAssignments = sptAssignmentChanges.getAdd(); if (addAssignments != null) { Set<String> addSpts = addAssignments.getServiceProfileTemplates(); if ((addSpts != null) && (!addSpts.isEmpty())) { _log.debug("Request specifies service profile templates to be added."); // Validate the requested URIs. checkServiceProfileTemplateURIs(addSpts, _dbClient); // Load a Set of the Compute Systems associated to current SPTs Map<URI, UCSServiceProfileTemplate> computeSystemToTemplateMap = new HashMap<URI, UCSServiceProfileTemplate>(); // Iterate over all SPTs currently associated to the CVP if (cvp.getServiceProfileTemplates() != null && !cvp.getServiceProfileTemplates().isEmpty()) { Collection<UCSServiceProfileTemplate> templates = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(cvp.getServiceProfileTemplates())); for (UCSServiceProfileTemplate template : templates) { // verify the SPT exists in the db ArgValidator.checkEntity(template, template.getId(), isIdEmbeddedInURL(template.getId())); computeSystemToTemplateMap.put(template.getComputeSystem(), template); } } // Iterate over the service profile templates and assign them to the CVP. StringSet currentAssignments = cvp.getServiceProfileTemplates(); Collection<UCSServiceProfileTemplate> addedTemplates = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(addSpts)); for (UCSServiceProfileTemplate addedTemplate : addedTemplates) { if ((currentAssignments != null) && (currentAssignments.contains(addedTemplate.getId().toString()))) { // Just ignore those already assigned _log.info("Compute Virtual Pool already assigned to service profile template {}", addedTemplate.getId() .toString()); continue; } // verify that the SPT is not associated to a Compute System already in use ArgValidator.checkEntity(addedTemplate, addedTemplate.getId(), isIdEmbeddedInURL(addedTemplate.getId())); UCSServiceProfileTemplate existingTemplate = computeSystemToTemplateMap.get(addedTemplate.getComputeSystem()); if (existingTemplate != null) { _log.debug("Compute system " + addedTemplate.getComputeSystem() + " already contains a spt " + existingTemplate); /* * TODO: For 2.2 release, we will not check if SPT is in use but will only check if vcp is in use * if(isServiceProfileTemplateInUse(cvp,existingTemplate)) { * _log.info("SPT " + existingTemplate + * " is already in use and cannot be disassociated and replaced with requested SPT " + * addedTemplate.getId().toString()); * throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getId(), * "Cannot replace service profile template that is already in use."); * } else { * _log.info("SPT " + existingTemplate + * " is not in use and will be disassociated and replaced with requested SPT " + * addedTemplate.getId().toString()); * sptsRemovedFromCvp.add(existingTemplate.getId().toString()); * } */ if (isComputeVirtualPoolInUse(cvp)) { _log.info("compute virtual pool is already in use and so SPT cannot be disassociated and replaced with requested SPT " + addedTemplate.getId().toString()); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot replace service profile template that is already in use."); } else { _log.info("compute virtual pool is not in use and so SPT will be disassociated and replaced with requested SPT " + addedTemplate.getId().toString()); sptsRemovedFromCvp.add(existingTemplate.getId().toString()); } } if (addedTemplate.getUpdating() == true) { _log.info("selected spt is an updating template. So validate..."); if (!computeSystemService.isUpdatingSPTValid(addedTemplate, _dbClient)) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Nic or hba names in updating service profile template " + addedTemplate.getLabel() + " do not match those in its boot policy."); } } if (!computeSystemService.isServiceProfileTemplateValidForVarrays(cvp.getVirtualArrays(), addedTemplate.getId())) { throw APIException.badRequests.sptIsNotValidForVarrays(addedTemplate.getLabel()); } validateServiceProfileTemplate(cvp, addedTemplate); sptsAddedToCvp.add(addedTemplate.getId().toString()); sptsForCvpUpdated = true; _log.debug("Compute Virtual Pool will be assigned to service profile template {}", addedTemplate.getId() .toASCIIString()); } } } // Validate that the Service Profile Templates to be unassigned from the // Compute Virtual Pool reference existing Service Profile Templates in the database // and remove them from the CVP. ServiceProfileTemplateAssignments removeAssignments = sptAssignmentChanges.getRemove(); if (removeAssignments != null) { Collection<UCSServiceProfileTemplate> removedTemplates = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(removeAssignments.getServiceProfileTemplates())); if ((removedTemplates != null) && (!removedTemplates.isEmpty())) { _log.debug("Request specifies service profile templates to be removed."); // Validate the requested URIs. // If vcp is in use, SPTs cannot be removed - for the 2.2 release if (isComputeVirtualPoolInUse(cvp)) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot remove service profile template since virtual compute pool is already in use."); } // Iterate over the service profile templates and unassign from the CVP StringSet currentAssignments = cvp.getServiceProfileTemplates(); for (UCSServiceProfileTemplate removedTemplate : removedTemplates) { if ((currentAssignments == null) || (!currentAssignments.contains(removedTemplate.getId().toString()))) { // Just ignore those not assigned. _log.debug("Compute Virtual Pool is not assigned to service profile template {}", removedTemplate.getId() .toString()); continue; } if (isServiceProfileTemplateInUse(cvp, removedTemplate)) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot remove service profile template already in use."); } sptsRemovedFromCvp.add(removedTemplate.getId().toString()); sptsForCvpUpdated = true; _log.info("Compute Virtual Pool will be unassigned from service profile template {}", removedTemplate.getId() .toString()); } } } // At this point all spt's being added have been verified // now make sure that only one spt per compute system Set<String> sptsCurrentAfterRemove = cvp.getServiceProfileTemplates(); if (removeAssignments != null) { Collection<UCSServiceProfileTemplate> removedTempls = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(removeAssignments.getServiceProfileTemplates())); Set<String> removedIDs = new HashSet<String>(); for (UCSServiceProfileTemplate rmvdTempl : removedTempls) { removedIDs.add(rmvdTempl.getId().toString()); } sptsCurrentAfterRemove.removeAll(removedIDs); } Set<URI> sptComputeSystems = new HashSet<URI>(); // Iterate over all SPTs in returned in the param stringset Collection<UCSServiceProfileTemplate> addedTemplates = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(sptsAddedToCvp)); for (UCSServiceProfileTemplate template : addedTemplates) { _log.debug("Adding SPT : " + template.getId().toString()); if (sptComputeSystems.contains(template.getComputeSystem())) { throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Service profile template already in use and associated to compute system."); } else { sptComputeSystems.add(template.getComputeSystem()); } } Collection<UCSServiceProfileTemplate> existingTemplates = _dbClient.queryObject(UCSServiceProfileTemplate.class, toUriList(sptsCurrentAfterRemove)); for (UCSServiceProfileTemplate template : existingTemplates) { _log.debug("Adding SPT : " + template.getId().toString()); if (sptComputeSystems.contains(template.getComputeSystem())) { throw APIException.badRequests .changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Duplicate compute system association. Only one service profile template can be associated to a compute system in a Compute Virtual Pool."); } else { sptComputeSystems.add(template.getComputeSystem()); } } } // Persist virtual array changes for the Compute Virtual Pool, if any. if (sptsForCvpUpdated) { if (!sptsAddedToCvp.isEmpty()) { cvp.addServiceProfileTemplates(sptsAddedToCvp); } if (!sptsRemovedFromCvp.isEmpty()) { cvp.removeServiceProfileTemplates(sptsRemovedFromCvp); } } return sptsForCvpUpdated; } /** * Verifies the service profile template assignment changes in the update request are * valid, else throws a bad request exception. * * @param cvp - A reference to a Compute Virtual Pool. * @param sptAssignmentChanges The service profile template assignment changes in a * compute virtual pool update request. */ private void verifySptAssignmentChanges(ComputeVirtualPool cvp, ServiceProfileTemplateAssignmentChanges sptAssignmentChanges) { // Verify the add/remove sets do not overlap. ServiceProfileTemplateAssignments addAssignments = sptAssignmentChanges.getAdd(); ServiceProfileTemplateAssignments removeAssignments = sptAssignmentChanges.getRemove(); if ((addAssignments != null) && (removeAssignments != null)) { Set<String> addSpts = addAssignments.getServiceProfileTemplates(); Set<String> removeSpts = removeAssignments.getServiceProfileTemplates(); if ((addSpts != null) && (removeSpts != null)) { Set<String> addSet = new HashSet<String>(addSpts); Set<String> removeSet = new HashSet<String>(removeSpts); addSet.retainAll(removeSet); if (!addSet.isEmpty()) { _log.error("Request specifies the same service profile templates (s) in both the add and remove lists {}", addSet); // TODO: add more specific exception throw APIException.badRequests.sameVirtualArrayInAddRemoveList(); } } } } /** * Validates that each of the passed virtual array ids reference an existing * virtual array in the database and throws a bad request exception when * an invalid id is found. * * @param dbClient A reference to a DB client. */ private void checkServiceProfileTemplateURIs(Set<String> sptIds, DbClient dbClient) { Set<String> invalidIds = new HashSet<String>(); if ((sptIds != null) && (!sptIds.isEmpty())) { Iterator<String> sptIdsIter = sptIds.iterator(); while (sptIdsIter.hasNext()) { URI sptURI = null; try { sptURI = URI.create(sptIdsIter.next()); UCSServiceProfileTemplate serviceProfileTemplate = dbClient.queryObject(UCSServiceProfileTemplate.class, sptURI); if (serviceProfileTemplate == null) { invalidIds.add(sptURI.toString()); } } catch (DatabaseException e) { if (sptURI != null) { invalidIds.add(sptURI.toString()); } } } } if (!invalidIds.isEmpty()) { throw APIException.badRequests.theURIsOfParametersAreNotValid("service profile templates", invalidIds); } } /** * Delete a Compute Virtual Pool * * @brief Delete a compute virtual pool * @param id The ID of Compute Virtual Pool * @return Response result */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/deactivate") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public Response deleteComputeVirtualPool(@PathParam("id") URI id) { ArgValidator.checkUri(id); ComputeVirtualPool cvp = _dbClient.queryObject(ComputeVirtualPool.class, id); ArgValidator.checkEntityNotNull(cvp, id, isIdEmbeddedInURL(id)); // make sure cvp is unused by CE ArgValidator.checkReference(ComputeVirtualPool.class, id, checkForDelete(cvp)); if (isComputeVirtualPoolInUse(cvp)) { throw APIException.badRequests.cannotRemoveVCP(cvp.getLabel()); } _dbClient.markForDeletion(cvp); recordOperation(OperationTypeEnum.DELETE_COMPUTE_VPOOL, VPOOL_DELETED_DESCRIPTION, cvp); return Response.ok().build(); } /** * Get collection of compute elements that match criteria in an existing Compute Virtual Pool * * @brief Get collection of compute elements that match an existing compute virtual pool * @param id The Compute Virtual Pool ID * @return ComputeElementListRestRep Collection of Compute Elements */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/compute-elements") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE }) public ComputeElementListRestRep getComputeElementsByPool(@PathParam("id") URI id) { ArgValidator.checkUri(id); ComputeVirtualPool cvp = _permissionsHelper.getObjectById(id, ComputeVirtualPool.class); ArgValidator.checkEntityNotNull(cvp, id, isIdEmbeddedInURL(id)); return extractComputeElements(cvp); } /** * List all instances of compute virtual pools * * @brief List all instances of compute virtual pools * @prereq none * @brief List all instances of compute virtual pools */ @POST @Path("/bulk") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public ComputeVirtualPoolBulkRep getBulkResources(BulkIdParam param) { return (ComputeVirtualPoolBulkRep) super.getBulkResources(param); } @Override public ComputeVirtualPoolBulkRep queryBulkResourceReps(List<URI> ids) { Iterator<ComputeVirtualPool> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); BulkList.ResourceFilter filter = new BulkList.ComputeVirtualPoolFilter(); return new ComputeVirtualPoolBulkRep(BulkList.wrapping(_dbIterator, COMPUTE_VPOOL_MAPPER, filter)); } private final ComputeVirtualPoolMapper COMPUTE_VPOOL_MAPPER = new ComputeVirtualPoolMapper(); private class ComputeVirtualPoolMapper implements Function<ComputeVirtualPool, ComputeVirtualPoolRestRep> { @Override public ComputeVirtualPoolRestRep apply(final ComputeVirtualPool vpool) { boolean inUse = isComputeVirtualPoolInUse(vpool); return toComputeVirtualPool(_dbClient, vpool, inUse); } } @Override protected ComputeVirtualPoolBulkRep queryFilteredBulkResourceReps(List<URI> ids) { if (isSystemOrRestrictedSystemAdmin()){ return queryBulkResourceReps(ids); } else { Iterator<ComputeVirtualPool> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); BulkList.ResourceFilter filter = new BulkList.ComputeVirtualPoolFilter(getUserFromContext(), _permissionsHelper); return new ComputeVirtualPoolBulkRep(BulkList.wrapping(_dbIterator, COMPUTE_VPOOL_MAPPER, filter)); } } private void validateMinMaxIntValues(Integer minVal, Integer maxVal, String minField, String maxField) { if (minVal != null && minVal != 0) { ArgValidator.checkFieldMinimum(minVal, 1, minField); } if (maxVal != null && maxVal != 0 && maxVal != -1) { if (minVal != null) { // Make sure Max is greater than or equal to the Min ArgValidator.checkFieldMinimum(maxVal, minVal, maxField); } else { ArgValidator.checkFieldMinimum(maxVal, 1, maxField); } } } /** * Record Bourne Event for the completed operations * * @param type * @param type * @param description * @param vpool */ private void recordVirtualPoolEvent(String type, String description, URI vpool) { RecordableBourneEvent event = new RecordableBourneEvent( /* String */type, /* tenant id */null, /* user id ?? */URI.create("ViPR-User"), /* project ID */null, /* VirtualPool */vpool, /* service */EVENT_SERVICE_TYPE, /* resource id */vpool, /* description */description, /* timestamp */System.currentTimeMillis(), /* extensions */"", /* native guid */null, /* record type */RecordType.Event.name(), /* Event Source */EVENT_SERVICE_SOURCE, /* Operational Status codes */"", /* Operational Status Descriptions */""); try { _evtMgr.recordEvents(event); } catch (Exception ex) { _log.error("Failed to record event. Event description: {}. Error: {}.", description, ex); } } public void recordOperation(OperationTypeEnum opType, String evDesc, Object... extParam) { String evType; evType = opType.getEvType(true); _log.info("opType: {} detail: {}", opType.toString(), evType + ':' + evDesc); ComputeVirtualPool computeVpool = (ComputeVirtualPool) extParam[0]; recordVirtualPoolEvent(evType, evDesc, computeVpool.getId()); StringBuilder vArrays = new StringBuilder(); if (computeVpool.getVirtualArrays() != null) { for (String varray : computeVpool.getVirtualArrays()) { vArrays.append(" "); vArrays.append(varray); } } switch (opType) { case CREATE_COMPUTE_VPOOL: auditOp(opType, true, null, computeVpool.getId().toString(), computeVpool.getLabel(), computeVpool.getSystemType(), vArrays.toString()); break; case UPDATE_COMPUTE_VPOOL: auditOp(opType, true, null, computeVpool.getId().toString(), computeVpool.getLabel(), computeVpool.getSystemType(), vArrays.toString()); break; case DELETE_COMPUTE_VPOOL: auditOp(opType, true, null, computeVpool.getId().toString(), computeVpool.getLabel(), computeVpool.getSystemType()); break; default: _log.error("unrecognized compute vpool operation type"); } } /** * Get compute virtual pool ACL * * @prereq none * @param id the URN of a ViPR VirtualPool * @brief Show ACL assignment for compute virtual pool * @return ACL Assignment details */ @GET @Path("/{id}/acl") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }) public ACLAssignments getAcls(@PathParam("id") URI id) { return getAclsOnVirtualPool(id); } /** * Add or remove individual compute virtual pool ACL entry(s). Request body must include at least one add or remove operation. * * @prereq none * @param id the URN of a ViPR VirtualPool * @param changes ACL assignment changes * @brief Add or remove compute virtual pool ACL entries * @return No data returned in response body */ @PUT @Path("/{id}/acl") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }, blockProxies = true) public ACLAssignments updateAcls(@PathParam("id") URI id, ACLAssignmentChanges changes) { ComputeVirtualPool vpool = (ComputeVirtualPool) queryResource(id); ArgValidator.checkEntityNotNull(vpool, id, isIdEmbeddedInURL(id)); _permissionsHelper.updateACLs(vpool, changes, new PermissionsHelper.UsageACLFilter(_permissionsHelper, vpool.getSystemType())); _dbClient.updateAndReindexObject(vpool); auditOp(OperationTypeEnum.MODIFY_VPOOL_ACL, true, null, vpool.getId().toString(), vpool.getLabel(), vpool.getSystemType()); return getAclsOnVirtualPool(id); } private ACLAssignments getAclsOnVirtualPool(URI id) { ComputeVirtualPool vpool = (ComputeVirtualPool) queryResource(id); ArgValidator.checkEntityNotNull(vpool, id, isIdEmbeddedInURL(id)); ACLAssignments response = new ACLAssignments(); response.setAssignments(_permissionsHelper.convertToACLEntries(vpool.getAcls())); return response; } private void updateOtherPoolsComputeElements(ComputeVirtualPool computeVirtualPoolToIgnore) { List<URI> computeVirtualPoolUris = _dbClient.queryByType(ComputeVirtualPool.class, true); Collection<ComputeVirtualPool> computeVirtualPools = _dbClient.queryObject(ComputeVirtualPool.class, computeVirtualPoolUris); for (ComputeVirtualPool computeVirtualPool : computeVirtualPools) { if (computeVirtualPool.getId().equals(computeVirtualPoolToIgnore.getId())) { continue; } if (computeVirtualPool.getUseMatchedElements()) { getMatchingCEsforCVPAttributes(computeVirtualPool); _dbClient.updateAndReindexObject(computeVirtualPool); } } } /** * Assign Compute Elements to the Compute Virtual Pool * * @brief Assign Compute Elements to the compute virtual pool * @param param The Compute Virtual Pool Compute Elements to be added and removed * @return ComputeVirtualPoolRestRep The updated Compute Virtual Pool */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/assign-matched-elements") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public ComputeVirtualPoolRestRep assignMatchedElements(@PathParam("id") URI id, ComputeVirtualPoolElementUpdateParam param) throws APIException { // Validate that Virtual Pool exists ArgValidator.checkFieldUriType(id, ComputeVirtualPool.class, "id"); ComputeVirtualPool cvp = this.queryObject(ComputeVirtualPool.class, id, true); _log.debug("Assign compute elements to compute pool " + cvp.getLabel()); if (cvp.getUseMatchedElements()) { _log.error("Cannot assign compute elements when pool is set to use automatic matching"); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot assign compute elements when pool is set to use automatic matching."); } StringSet currentElements = new StringSet(); if (cvp.getMatchedComputeElements() != null) { currentElements.addAll(cvp.getMatchedComputeElements()); } _log.debug("Currently " + currentElements.size() + " existing compute elements: " + currentElements); boolean addRequest = param.getComputeVirtualPoolAssignmentChanges().getAdd() != null && param.getComputeVirtualPoolAssignmentChanges().getAdd().getComputeElements() != null; if (addRequest) { Set<String> addElementsUris = param.getComputeVirtualPoolAssignmentChanges().getAdd().getComputeElements(); _log.debug("Add " + addElementsUris.size() + " compute elements: " + addElementsUris); Collection<ComputeElement> addElements = _dbClient.queryObject(ComputeElement.class, toUriList(addElementsUris)); // Validate // object // exists if (addElementsUris.size() != addElements.size()) { _log.error("Invalid add compute element(s) specified - Requested " + addElementsUris.size() + " but only " + addElements.size() + " found"); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Invalid add compute element(s) specified."); } List<URI> staticCeUris = findAllStaticallyAssignedComputeElementsInOtherPools(cvp); for (ComputeElement computeElement : addElements) { if (staticCeUris.contains(computeElement.getId())) { _log.error("Compute element " + computeElement.getId() + " already statically assigned to a different pool"); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Cannot assign compute element(s) already manually assigned to different pool(s)."); } } // Add against the current collection of compute elements for (String computeElementUriString : addElementsUris) { boolean added = currentElements.add(computeElementUriString); _log.info("Compute pool " + cvp.getLabel() + " already contained compute element " + computeElementUriString + ": " + added); } } boolean removeRequest = param.getComputeVirtualPoolAssignmentChanges().getRemove() != null && param.getComputeVirtualPoolAssignmentChanges().getRemove().getComputeElements() != null; if (removeRequest) { Set<String> removeElementsUris = param.getComputeVirtualPoolAssignmentChanges().getRemove().getComputeElements(); _log.debug("Remove " + removeElementsUris.size() + " compute elements: " + removeElementsUris); Collection<ComputeElement> removeElements = _dbClient.queryObject(ComputeElement.class, toUriList(removeElementsUris)); // Validate // object // exists if (removeElementsUris.size() != removeElements.size()) { _log.error("Invalid remove compute element(s) specified - Requested " + removeElementsUris.size() + " but only " + removeElements.size() + " found"); throw APIException.badRequests.changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Invalid remove compute element(s) specified."); } // Remove against the current collection of compute elements for (String computeElementUriString : removeElementsUris) { boolean removed = currentElements.remove(computeElementUriString); _log.debug("Compute pool " + cvp.getLabel() + " needed removal of compute element " + computeElementUriString + ": " + removed); } removeHostToCVPRelation(removeElements, cvp); } Collection<ComputeElement> assignedElements = _dbClient.queryObject(ComputeElement.class, toUriList(currentElements)); // Validate // object // exists for (ComputeElement element : assignedElements) { boolean inUse = false; if (!element.getAvailable()) { inUse = true; } // validate that this is element matches the current vcp criteria try { validateComputeElement(cvp, element); } catch (APIException e) { _log.warn("Compute Element " + element.getLabel() + ":" + element.getDn() + " is in use(" + inUse + ") and does not meet criteria " + e.toString()); /* * Since we are disallowing more restrictive changes if the VCP is in use, the if block below will not be used for the 2.2 * release. */ if (inUse) { throw APIException.badRequests .changeToComputeVirtualPoolNotSupported(cvp.getLabel(), "Updates to pool not allowed because compute virtual pool is already in use and some compute elements being assigned do not meet criteria."); } currentElements.remove(element.getId().toString()); // if ces not in use then simply remove _log.warn("Compute Element does not meet criteria; so being removed"); } } cvp.setMatchedComputeElements(currentElements); updateHostToCVPRelation(cvp); _dbClient.updateAndReindexObject(cvp); // Crucial that we save the static assignments before running updateOtherPoolsComputeElements // so that the dynamic matching reassignments happen with latest static assignments updateOtherPoolsComputeElements(cvp); return toComputeVirtualPool(_dbClient, cvp, isComputeVirtualPoolInUse(cvp)); } /** * Get object specific permissions filter */ @Override public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user, PermissionsHelper permissionsHelper) { return new ComputeVirtualPoolResRepFilter(user, permissionsHelper); } private List<Host> getHostsProvisionedFromPool(ComputeVirtualPool cvp) { List<Host> hostList = new ArrayList<Host>(); URIQueryResultList hostURIs = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory .getVirtualComputePoolHostConstraint(cvp.getId()), hostURIs); Iterator<URI> iter = hostURIs.iterator(); while (iter.hasNext()) { URI hostURI = iter.next(); Host host = _dbClient.queryObject(Host.class, hostURI); if (host != null && !host.getInactive()) { hostList.add(host); } else { _log.error("Can't find host {} in the database " + "or the host is marked for deletion", hostURI); } } return hostList; } public static class ComputeVirtualPoolResRepFilter<E extends RelatedResourceRep> extends ResRepFilter<E> { public ComputeVirtualPoolResRepFilter(StorageOSUser user, PermissionsHelper permissionsHelper) { super(user, permissionsHelper); } @Override public boolean isAccessible(E resrep) { URI id = resrep.getId(); ComputeVirtualPool resource = _permissionsHelper.getObjectById(id, ComputeVirtualPool.class); if (resource == null) { return false; } return isComputeVirtualPoolAccessible(resource); } } private void updateHostToCVPRelation(ComputeVirtualPool cvp) { Collection<ComputeElement> computeElements = _dbClient.queryObject(ComputeElement.class, toUriList(cvp.getMatchedComputeElements())); List<Host> updatedHosts = Lists.newArrayList(); for (ComputeElement computeElement : computeElements) { List<Host> hosts = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, Host.class, ContainmentConstraint.Factory.getContainedObjectsConstraint(computeElement.getId(), Host.class, "computeElement")); for (Host host : hosts) { if (NullColumnValueGetter.isNullURI(host.getComputeVirtualPoolId()) || !cvp.getId().equals(host.getComputeVirtualPoolId())) { host.setComputeVirtualPoolId(cvp.getId()); updatedHosts.add(host); } } } if (CollectionUtils.isNotEmpty(updatedHosts)) { _dbClient.updateObject(updatedHosts); } } private void removeHostToCVPRelation(Collection<ComputeElement> removeElements, ComputeVirtualPool cvp) { List<Host> updatedHosts = Lists.newArrayList(); for (ComputeElement computeElement : removeElements) { List<Host> hosts = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, Host.class, ContainmentConstraint.Factory.getContainedObjectsConstraint(computeElement.getId(), Host.class, "computeElement")); for (Host host : hosts) { if (!NullColumnValueGetter.isNullURI(host.getComputeVirtualPoolId()) && host.getComputeVirtualPoolId().equals(cvp.getId())) { host.setComputeVirtualPoolId(NullColumnValueGetter.getNullURI()); updatedHosts.add(host); } } } if (CollectionUtils.isNotEmpty(updatedHosts)) { _dbClient.updateObject(updatedHosts); } } }