Search in sources :

Example 1 with EntitlementRefusedException

use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.

the class CandlepinPoolManager method getBestPoolsForHost.

/**
 * Here we pick uncovered products from the guest where no virt-only
 * subscriptions exist, and have the host bind non-zero virt_limit
 * subscriptions in order to generate pools for the guest to bind later.
 *
 * @param guest whose products we want to provide
 * @param host to bind entitlements to
 * @param entitleDate
 * @param owner
 * @param serviceLevelOverride
 * @return PoolQuantity list to attempt to attach
 * @throws EntitlementRefusedException if unable to bind
 */
@Override
@SuppressWarnings("checkstyle:methodlength")
public List<PoolQuantity> getBestPoolsForHost(Consumer guest, Consumer host, Date entitleDate, String ownerId, String serviceLevelOverride, Collection<String> fromPools) throws EntitlementRefusedException {
    Map<String, ValidationResult> failedResults = new HashMap<>();
    log.debug("Looking up best pools for host: {}", host);
    boolean tempLevel = false;
    if (StringUtils.isEmpty(host.getServiceLevel())) {
        host.setServiceLevel(guest.getServiceLevel());
        tempLevel = true;
    }
    Date activePoolDate = entitleDate;
    if (entitleDate == null) {
        activePoolDate = new Date();
    }
    PoolFilterBuilder poolFilter = new PoolFilterBuilder();
    poolFilter.addIdFilters(fromPools);
    List<Pool> allOwnerPools = this.listAvailableEntitlementPools(host, null, ownerId, null, null, activePoolDate, false, poolFilter, null, false, false, null).getPageData();
    log.debug("Found {} total pools in org.", allOwnerPools.size());
    logPools(allOwnerPools);
    List<Pool> allOwnerPoolsForGuest = this.listAvailableEntitlementPools(guest, null, ownerId, null, null, activePoolDate, false, poolFilter, null, false, false, null).getPageData();
    log.debug("Found {} total pools already available for guest", allOwnerPoolsForGuest.size());
    logPools(allOwnerPoolsForGuest);
    for (Entitlement ent : host.getEntitlements()) {
        // filter out pools that are attached, there is no need to
        // complete partial stacks, as they are already granting
        // virtual pools
        log.debug("Removing pool host is already entitled to: {}", ent.getPool());
        allOwnerPools.remove(ent.getPool());
    }
    List<Pool> filteredPools = new LinkedList<>();
    ComplianceStatus guestCompliance = complianceRules.getStatus(guest, entitleDate, false);
    Set<String> tmpSet = new HashSet<>();
    // we only want to heal red products, not yellow
    tmpSet.addAll(guestCompliance.getNonCompliantProducts());
    log.debug("Guest's non-compliant products: {}", Util.collectionToString(tmpSet));
    /*Do not attempt to create subscriptions for products that
          already have virt_only pools available to the guest */
    Set<String> productsToRemove = getProductsToRemove(allOwnerPoolsForGuest, tmpSet);
    log.debug("Guest already will have virt-only pools to cover: {}", Util.collectionToString(productsToRemove));
    tmpSet.removeAll(productsToRemove);
    String[] productIds = tmpSet.toArray(new String[] {});
    if (log.isDebugEnabled()) {
        log.debug("Attempting host autobind for guest products: {}", Util.collectionToString(tmpSet));
    }
    // Bulk fetch our provided and derived provided product IDs so we're not hitting the DB
    // several times for this lookup.
    Map<String, Set<String>> providedProductIds = this.poolCurator.getProvidedProductIds(allOwnerPools);
    Map<String, Set<String>> derivedProvidedProductIds = this.poolCurator.getDerivedProvidedProductIds(allOwnerPools);
    for (Pool pool : allOwnerPools) {
        boolean providesProduct = false;
        // and we only need to check that it's non-zero
        if (pool.getProduct().hasAttribute(Product.Attributes.VIRT_LIMIT) && !pool.getProduct().getAttributeValue(Product.Attributes.VIRT_LIMIT).equals("0")) {
            Map<String, Set<String>> providedProductMap;
            String baseProductId;
            // Determine which set of provided products we should use...
            if (pool.getDerivedProduct() != null) {
                providedProductMap = derivedProvidedProductIds;
                baseProductId = pool.getDerivedProduct().getId();
            } else {
                providedProductMap = providedProductIds;
                baseProductId = pool.getProduct().getId();
            }
            // Add the base product to the list of derived provided products...
            Set<String> poolProvidedProductIds = providedProductMap.get(pool.getId());
            if (baseProductId != null) {
                if (poolProvidedProductIds != null) {
                    poolProvidedProductIds.add(baseProductId);
                } else {
                    poolProvidedProductIds = Collections.<String>singleton(baseProductId);
                }
            }
            // Check if the pool provides any of the specified products
            if (poolProvidedProductIds != null) {
                for (String productId : productIds) {
                    // provides anything for the guest, otherwise we use the parent.
                    if (poolProvidedProductIds.contains(productId)) {
                        log.debug("Found virt_limit pool providing product {}: {}", productId, pool);
                        providesProduct = true;
                        break;
                    }
                }
            }
        }
        if (providesProduct) {
            ValidationResult result = enforcer.preEntitlement(host, pool, 1, CallerType.BEST_POOLS);
            if (result.hasErrors() || result.hasWarnings()) {
                // Just keep the last one around, if we need it
                failedResults.put(pool.getId(), result);
                if (log.isDebugEnabled()) {
                    log.debug("Pool filtered from candidates due to failed rule(s): {}", pool);
                    log.debug("  warnings: {}", Util.collectionToString(result.getWarnings()));
                    log.debug("  errors: {}", Util.collectionToString(result.getErrors()));
                }
            } else {
                filteredPools.add(pool);
            }
        }
    }
    // Only throw refused exception if we actually hit the rules:
    if (filteredPools.size() == 0 && !failedResults.isEmpty()) {
        throw new EntitlementRefusedException(failedResults);
    }
    ComplianceStatus hostCompliance = complianceRules.getStatus(host, entitleDate, false);
    log.debug("Host pools being sent to rules: {}", filteredPools.size());
    logPools(filteredPools);
    List<PoolQuantity> enforced = autobindRules.selectBestPools(host, productIds, filteredPools, hostCompliance, serviceLevelOverride, poolCurator.retrieveServiceLevelsForOwner(ownerId, true), true);
    if (log.isDebugEnabled()) {
        log.debug("Host selectBestPools returned {} pools: ", enforced.size());
        for (PoolQuantity poolQuantity : enforced) {
            log.debug("  " + poolQuantity.getPool());
        }
    }
    if (tempLevel) {
        host.setServiceLevel("");
        // complianceRules.getStatus may have persisted the host with the temp service level,
        // so we need to be certain we undo that.
        consumerCurator.update(host);
    }
    return enforced;
}
Also used : PoolQuantity(org.candlepin.model.PoolQuantity) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ComplianceStatus(org.candlepin.policy.js.compliance.ComplianceStatus) EntitlementRefusedException(org.candlepin.policy.EntitlementRefusedException) ValidationResult(org.candlepin.policy.ValidationResult) Date(java.util.Date) LinkedList(java.util.LinkedList) PoolFilterBuilder(org.candlepin.model.PoolFilterBuilder) Pool(org.candlepin.model.Pool) Entitlement(org.candlepin.model.Entitlement) HashSet(java.util.HashSet)

Example 2 with EntitlementRefusedException

use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.

the class Entitler method bindByProducts.

/**
 * Force option is used to heal entire org
 *
 * @param data AutobindData encapsulating data required for an autobind request
 * @param force heal host even if it has autoheal disabled
 * @return List of Entitlements
 * @throws AutobindDisabledForOwnerException when an autobind attempt is made and the owner
 *         has it disabled.
 */
@Transactional
public List<Entitlement> bindByProducts(AutobindData data, boolean force) throws AutobindDisabledForOwnerException {
    Consumer consumer = data.getConsumer();
    Owner owner = data.getOwner();
    if (!consumer.isDev() && owner.isAutobindDisabled()) {
        log.info("Skipping auto-attach for consumer '{}'. Auto-attach is disabled for owner {}.", consumer, owner.getKey());
        throw new AutobindDisabledForOwnerException(i18n.tr("Auto-attach is disabled for owner \"{0}\".", owner.getKey()));
    }
    // entitlements based on the planned design of the subscriptions
    if (consumer.hasFact("virt.uuid") && !consumer.isDev()) {
        String guestUuid = consumer.getFact("virt.uuid");
        // Remove any expired unmapped guest entitlements
        revokeUnmappedGuestEntitlements(consumer);
        // Scoped to the consumer's organization.  Even in the event of sharing, a guest in one
        // organization should not be able to compel a heal in an another organization
        Consumer host = consumerCurator.getHost(consumer, consumer.getOwnerId());
        if (host != null && (force || host.isAutoheal())) {
            log.info("Attempting to heal host machine with UUID \"{}\" for guest with UUID \"{}\"", host.getUuid(), consumer.getUuid());
            if (!StringUtils.equals(host.getServiceLevel(), consumer.getServiceLevel())) {
                log.warn("Host with UUID \"{}\" has a service level \"{}\" that does not match" + " that of the guest with UUID \"{}\" and service level \"{}\"", host.getUuid(), host.getServiceLevel(), consumer.getUuid(), consumer.getServiceLevel());
            }
            try {
                List<Entitlement> hostEntitlements = poolManager.entitleByProductsForHost(consumer, host, data.getOnDate(), data.getPossiblePools());
                log.debug("Granted host {} entitlements", hostEntitlements.size());
                sendEvents(hostEntitlements);
            } catch (Exception e) {
                // log and continue, this should NEVER block
                log.debug("Healing failed for host UUID {} with message: {}", host.getUuid(), e.getMessage());
            }
            /* Consumer is stale at this point.  Note that we use find() instead of
                 * findByUuid() or getConsumer() since the latter two methods are secured
                 * to a specific host principal and bindByProducts can get called when
                 * a guest is switching hosts */
            consumer = consumerCurator.find(consumer.getId());
            data.setConsumer(consumer);
        }
    }
    if (consumer.isDev()) {
        if (config.getBoolean(ConfigProperties.STANDALONE) || !poolCurator.hasActiveEntitlementPools(consumer.getOwnerId(), null)) {
            throw new ForbiddenException(i18n.tr("Development units may only be used on hosted servers" + " and with orgs that have active subscriptions."));
        }
        // Look up the dev pool for this consumer, and if not found
        // create one. If a dev pool already exists, remove it and
        // create a new one.
        String sku = consumer.getFact("dev_sku");
        Pool devPool = poolCurator.findDevPool(consumer);
        if (devPool != null) {
            poolManager.deletePool(devPool);
        }
        devPool = poolManager.createPool(assembleDevPool(consumer, owner, sku));
        data.setPossiblePools(Arrays.asList(devPool.getId()));
        data.setProductIds(new String[] { sku });
    }
    // Attempt to create entitlements:
    try {
        // the pools are only used to bind the guest
        List<Entitlement> entitlements = poolManager.entitleByProducts(data);
        log.debug("Created entitlements: {}", entitlements);
        return entitlements;
    } catch (EntitlementRefusedException e) {
        // TODO: Could be multiple errors, but we'll just report the first one for now
        String productId = "Unknown Product";
        if (data.getProductIds().length > 0) {
            productId = data.getProductIds()[0];
        }
        throw new ForbiddenException(messageTranslator.productErrorToMessage(productId, e.getResults().values().iterator().next().getErrors().get(0)));
    }
}
Also used : Owner(org.candlepin.model.Owner) ForbiddenException(org.candlepin.common.exceptions.ForbiddenException) Consumer(org.candlepin.model.Consumer) EntitlementRefusedException(org.candlepin.policy.EntitlementRefusedException) Pool(org.candlepin.model.Pool) Entitlement(org.candlepin.model.Entitlement) BadRequestException(org.candlepin.common.exceptions.BadRequestException) ForbiddenException(org.candlepin.common.exceptions.ForbiddenException) EntitlementRefusedException(org.candlepin.policy.EntitlementRefusedException) Transactional(com.google.inject.persist.Transactional)

Example 3 with EntitlementRefusedException

use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.

the class RevocationOp method execute.

@Transactional
public void execute(PoolManager poolManager) {
    Collection<Pool> overflowing = new ArrayList<>();
    for (Pool pool : pools) {
        if (pool.isOverflowing()) {
            overflowing.add(pool);
        }
    }
    if (overflowing.isEmpty()) {
        return;
    }
    overflowing = poolCurator.lockAndLoad(overflowing);
    for (Pool pool : overflowing) {
        poolNewConsumed.put(pool, pool.getConsumed());
        List<Pool> shared = poolCurator.listSharedPoolsOf(pool);
        if (!shared.isEmpty()) {
            sharedPools.put(pool, shared);
            // first determine shared pool counts where allotted units are not in use
            reduceSharedPools(pool);
        }
        // we then start revoking the existing entitlements
        determineExcessEntitlements(pool);
    }
    // revoke the entitlements amassed above
    poolManager.revokeEntitlements(new ArrayList<>(entitlementsToRevoke));
    // We have to wait until we get here so that share pool entitlements we want revoked are gone
    for (Entitlement entitlement : shareEntitlementsToAdjust.keySet()) {
        try {
            poolManager.adjustEntitlementQuantity(entitlement.getConsumer(), entitlement, shareEntitlementsToAdjust.get(entitlement).intValue());
        } catch (EntitlementRefusedException e) {
            // TODO: Could be multiple errors, but we'll just report the first one for now:
            throw new ForbiddenException(e.getResults().values().iterator().next().getErrors().get(0).toString());
        }
    }
}
Also used : ForbiddenException(org.candlepin.common.exceptions.ForbiddenException) EntitlementRefusedException(org.candlepin.policy.EntitlementRefusedException) ArrayList(java.util.ArrayList) Pool(org.candlepin.model.Pool) Entitlement(org.candlepin.model.Entitlement) Transactional(com.google.inject.persist.Transactional)

Example 4 with EntitlementRefusedException

use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.

the class PoolManagerTest method testEntitlebyProductRetry.

@Test
public void testEntitlebyProductRetry() throws Exception {
    Product product = TestUtil.createProduct();
    List<Pool> pools = new ArrayList<>();
    Pool pool1 = TestUtil.createPool(product);
    pool1.setId("poolId1");
    pools.add(pool1);
    Pool pool2 = TestUtil.createPool(product);
    pool2.setId("poolId2");
    pools.add(pool2);
    Date now = new Date();
    Map<String, ValidationResult> resultMap = new HashMap<>();
    ValidationResult result = mock(ValidationResult.class);
    resultMap.put("poolId1", result);
    resultMap.put("poolId2", result);
    Page page = mock(Page.class);
    when(page.getPageData()).thenReturn(pools);
    when(mockPoolCurator.listAvailableEntitlementPools(any(Consumer.class), any(String.class), any(String.class), any(String.class), eq(now), any(PoolFilterBuilder.class), any(PageRequest.class), anyBoolean(), anyBoolean(), anyBoolean(), any(Date.class))).thenReturn(page);
    CandlepinQuery mockQuery = mock(CandlepinQuery.class);
    when(mockPoolCurator.listAllByIds(any(List.class))).thenReturn(mockQuery);
    List<Pool> poolList = Arrays.asList(pool1);
    when(mockQuery.iterator()).thenReturn(poolList.listIterator()).thenReturn(poolList.listIterator()).thenReturn(poolList.listIterator()).thenReturn(poolList.listIterator());
    when(enforcerMock.preEntitlement(any(Consumer.class), anyCollectionOf(PoolQuantity.class), any(CallerType.class))).thenReturn(resultMap);
    when(result.isSuccessful()).thenReturn(false);
    List<ValidationError> errors = new ArrayList<>();
    errors.add(new ValidationError("rulefailed.no.entitlements.available"));
    when(result.getErrors()).thenReturn(errors);
    List<PoolQuantity> bestPools = new ArrayList<>();
    bestPools.add(new PoolQuantity(pool1, 1));
    when(autobindRules.selectBestPools(any(Consumer.class), any(String[].class), any(List.class), any(ComplianceStatus.class), any(String.class), any(Set.class), eq(false))).thenReturn(bestPools);
    AutobindData data = AutobindData.create(TestUtil.createConsumer(owner), owner).forProducts(new String[] { product.getUuid() }).on(now);
    doNothing().when(mockPoolCurator).flush();
    try {
        List<Entitlement> e = manager.entitleByProducts(data);
        fail();
    } catch (EntitlementRefusedException e) {
        assertNotNull(e);
        verify(autobindRules, times(4)).selectBestPools(any(Consumer.class), any(String[].class), any(List.class), any(ComplianceStatus.class), any(String.class), any(Set.class), eq(false));
    }
}
Also used : PoolQuantity(org.candlepin.model.PoolQuantity) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) EntitlementRefusedException(org.candlepin.policy.EntitlementRefusedException) ArrayList(java.util.ArrayList) ConsumerInstalledProduct(org.candlepin.model.ConsumerInstalledProduct) Product(org.candlepin.model.Product) Page(org.candlepin.common.paging.Page) CandlepinQuery(org.candlepin.model.CandlepinQuery) Matchers.anyString(org.mockito.Matchers.anyString) CallerType(org.candlepin.policy.js.entitlement.Enforcer.CallerType) ValidationResult(org.candlepin.policy.ValidationResult) PageRequest(org.candlepin.common.paging.PageRequest) Consumer(org.candlepin.model.Consumer) PoolFilterBuilder(org.candlepin.model.PoolFilterBuilder) Pool(org.candlepin.model.Pool) ArrayList(java.util.ArrayList) List(java.util.List) LinkedList(java.util.LinkedList) Matchers.anyList(org.mockito.Matchers.anyList) AutobindData(org.candlepin.resource.dto.AutobindData) ValidationError(org.candlepin.policy.ValidationError) ComplianceStatus(org.candlepin.policy.js.compliance.ComplianceStatus) Date(java.util.Date) Entitlement(org.candlepin.model.Entitlement) Test(org.junit.Test)

Example 5 with EntitlementRefusedException

use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.

the class EntitlerJobTest method respondWithValidationErrors.

@Test
public void respondWithValidationErrors() throws JobExecutionException, EntitlementRefusedException {
    PoolIdAndQuantity[] pQs = new PoolIdAndQuantity[1];
    pQs[0] = new PoolIdAndQuantity("pool10", 1);
    JobDetail detail = EntitlerJob.bindByPoolAndQuantities(consumer, owner.getKey(), pQs);
    JobExecutionContext ctx = mock(JobExecutionContext.class);
    when(ctx.getMergedJobDataMap()).thenReturn(detail.getJobDataMap());
    HashMap<String, ValidationResult> mapResult = new HashMap<>();
    ValidationResult result = new ValidationResult();
    result.addError("rulefailed.no.entitlements.available");
    mapResult.put("hello", result);
    when(e.bindByPoolQuantities(eq(consumerUuid), anyMapOf(String.class, Integer.class))).thenThrow(new EntitlementRefusedException(mapResult));
    EntitlerJob job = new EntitlerJob(e, null, pC, i18n);
    injector.injectMembers(job);
    Pool p = new Pool();
    p.setId("hello");
    CandlepinQuery cqmock = mock(CandlepinQuery.class);
    when(cqmock.iterator()).thenReturn(Arrays.asList(p).iterator());
    when(pC.listAllByIds(anyListOf(String.class))).thenReturn(cqmock);
    job.execute(ctx);
    ArgumentCaptor<Object> argumentCaptor = ArgumentCaptor.forClass(Object.class);
    verify(ctx).setResult(argumentCaptor.capture());
    List<PoolIdAndErrors> resultErrors = (List<PoolIdAndErrors>) argumentCaptor.getValue();
    assertEquals(1, resultErrors.size());
    assertEquals("hello", resultErrors.get(0).getPoolId());
    assertEquals(1, resultErrors.get(0).getErrors().size());
    assertEquals("No subscriptions are available from the pool with ID \"hello\".", resultErrors.get(0).getErrors().get(0));
}
Also used : PoolIdAndQuantity(org.candlepin.model.dto.PoolIdAndQuantity) PoolIdAndErrors(org.candlepin.model.dto.PoolIdAndErrors) HashMap(java.util.HashMap) EntitlementRefusedException(org.candlepin.policy.EntitlementRefusedException) CandlepinQuery(org.candlepin.model.CandlepinQuery) ValidationResult(org.candlepin.policy.ValidationResult) JobDetail(org.quartz.JobDetail) JobExecutionContext(org.quartz.JobExecutionContext) Pool(org.candlepin.model.Pool) ArrayList(java.util.ArrayList) List(java.util.List) Test(org.junit.Test)

Aggregations

EntitlementRefusedException (org.candlepin.policy.EntitlementRefusedException)16 Pool (org.candlepin.model.Pool)13 HashMap (java.util.HashMap)10 ValidationResult (org.candlepin.policy.ValidationResult)8 Entitlement (org.candlepin.model.Entitlement)7 PoolQuantity (org.candlepin.model.PoolQuantity)7 ArrayList (java.util.ArrayList)5 ForbiddenException (org.candlepin.common.exceptions.ForbiddenException)4 Transactional (com.google.inject.persist.Transactional)3 Date (java.util.Date)3 HashSet (java.util.HashSet)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3 Set (java.util.Set)3 Consumer (org.candlepin.model.Consumer)3 Owner (org.candlepin.model.Owner)3 PoolFilterBuilder (org.candlepin.model.PoolFilterBuilder)3 Product (org.candlepin.model.Product)3 ValidationError (org.candlepin.policy.ValidationError)3 ComplianceStatus (org.candlepin.policy.js.compliance.ComplianceStatus)3