use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.
the class EntitlerJob method toExecute.
@Override
public void toExecute(JobExecutionContext ctx) throws JobExecutionException {
try {
JobDataMap map = ctx.getMergedJobDataMap();
String uuid = (String) map.get(JobStatus.TARGET_ID);
PoolIdAndQuantity[] poolQuantities = (PoolIdAndQuantity[]) map.get("pool_and_quantities");
Map<String, Integer> poolMap = new HashMap<>();
for (PoolIdAndQuantity poolIdAndQuantity : poolQuantities) {
poolMap.put(poolIdAndQuantity.getPoolId(), poolIdAndQuantity.getQuantity());
}
List<Entitlement> ents = entitler.bindByPoolQuantities(uuid, poolMap);
entitler.sendEvents(ents);
PoolIdAndQuantity[] consumed = new PoolIdAndQuantity[ents.size()];
for (int i = 0; i < ents.size(); i++) {
consumed[i] = new PoolIdAndQuantity(ents.get(i).getPool().getId(), ents.get(i).getQuantity());
}
ctx.setResult(Arrays.asList(consumed));
poolCurator.clear();
} catch (EntitlementRefusedException e) {
log.error("EntitlerJob encountered a problem, translating errors", e);
Map<String, ValidationResult> validationResults = e.getResults();
EntitlementRulesTranslator translator = new EntitlementRulesTranslator(i18n);
List<PoolIdAndErrors> poolErrors = new ArrayList<>();
for (Pool pool : poolCurator.listAllByIds(validationResults.keySet())) {
List<String> errorMessages = new ArrayList<>();
for (ValidationError error : validationResults.get(pool.getId()).getErrors()) {
errorMessages.add(translator.poolErrorToMessage(pool, error));
}
poolErrors.add(new PoolIdAndErrors(pool.getId(), errorMessages));
}
ctx.setResult(poolErrors);
}// so that the job will be properly cleaned up on failure.
catch (Exception e) {
log.error("EntitlerJob encountered a problem.", e);
throw new JobExecutionException(e.getMessage(), e, false);
}
}
use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.
the class Entitler method bindByPoolQuantity.
public List<Entitlement> bindByPoolQuantity(Consumer consumer, String poolId, Integer quantity) {
Map<String, Integer> poolMap = new HashMap<>();
poolMap.put(poolId, quantity);
try {
return bindByPoolQuantities(consumer, poolMap);
} catch (EntitlementRefusedException e) {
// TODO: Could be multiple errors, but we'll just report the first
// one for now
Pool pool = poolCurator.find(poolId);
throw new ForbiddenException(messageTranslator.poolErrorToMessage(pool, e.getResults().get(poolId).getErrors().get(0)));
}
}
use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.
the class Entitler method getDryRun.
/**
* Entitles the given Consumer to the given Product. Will seek out pools
* which provide access to this product, either directly or as a child, and
* select the best one based on a call to the rules engine.
*
* @param consumer The consumer being entitled.
* @return List of Entitlements
*/
public List<PoolQuantity> getDryRun(Consumer consumer, Owner owner, String serviceLevelOverride) {
List<PoolQuantity> result = new ArrayList<>();
try {
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));
result.add(new PoolQuantity(devPool, 1));
} else {
result = poolManager.getBestPools(consumer, null, null, owner.getId(), serviceLevelOverride, null);
}
log.debug("Created Pool Quantity list: {}", result);
} catch (EntitlementRefusedException e) {
// to the process
if (log.isDebugEnabled()) {
log.debug("consumer {} dry-run errors:", consumer.getUuid());
for (Entry<String, ValidationResult> entry : e.getResults().entrySet()) {
log.debug("errors for pool id: {}", entry.getKey());
for (ValidationError error : entry.getValue().getErrors()) {
log.debug(error.getResourceKey());
}
}
}
}
return result;
}
use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.
the class CandlepinPoolManager method getBestPools.
@Override
public List<PoolQuantity> getBestPools(Consumer consumer, String[] productIds, Date entitleDate, String ownerId, String serviceLevelOverride, Collection<String> fromPools) throws EntitlementRefusedException {
Map<String, ValidationResult> failedResults = new HashMap<>();
Date activePoolDate = entitleDate;
if (entitleDate == null) {
activePoolDate = new Date();
}
PoolFilterBuilder poolFilter = new PoolFilterBuilder();
poolFilter.addIdFilters(fromPools);
List<Pool> allOwnerPools = this.listAvailableEntitlementPools(consumer, null, ownerId, null, null, activePoolDate, false, poolFilter, null, false, false, null).getPageData();
List<Pool> filteredPools = new LinkedList<>();
// We have to check compliance status here so we can replace an empty
// array of product IDs with the array the consumer actually needs. (i.e. during
// a healing request)
ComplianceStatus compliance = complianceRules.getStatus(consumer, entitleDate, false);
if (productIds == null || productIds.length == 0) {
log.debug("No products specified for bind, checking compliance to see what is needed.");
Set<String> tmpSet = new HashSet<>();
tmpSet.addAll(compliance.getNonCompliantProducts());
tmpSet.addAll(compliance.getPartiallyCompliantProducts().keySet());
productIds = tmpSet.toArray(new String[] {});
}
if (log.isDebugEnabled()) {
log.debug("Attempting for products on date: {}", entitleDate);
for (String productId : productIds) {
log.debug(" {}", productId);
}
}
// Bulk fetch our provided product IDs so we're not hitting the DB several times
// for this lookup.
Map<String, Set<String>> providedProductIds = this.poolCurator.getProvidedProductIds(allOwnerPools);
for (Pool pool : allOwnerPools) {
boolean providesProduct = false;
// We want to complete partial stacks if possible, even if they do not provide any products
Product poolProduct = pool.getProduct();
String stackingId = poolProduct.getAttributeValue(Product.Attributes.STACKING_ID);
if (stackingId != null && compliance.getPartialStacks().containsKey(stackingId)) {
providesProduct = true;
} else {
Set<String> poolProvidedProductIds = providedProductIds.get(pool.getId());
String poolProductId = pool.getProduct() != null ? pool.getProduct().getId() : null;
if (poolProductId != null) {
// Add the base product to our list of "provided" products
if (poolProvidedProductIds != null) {
poolProvidedProductIds.add(poolProductId);
} else {
poolProvidedProductIds = Collections.singleton(poolProductId);
}
}
if (poolProvidedProductIds != null) {
for (String productId : productIds) {
if (poolProvidedProductIds.contains(productId)) {
providesProduct = true;
break;
}
}
}
}
if (providesProduct) {
ValidationResult result = enforcer.preEntitlement(consumer, pool, 1, CallerType.BEST_POOLS);
if (result.hasErrors() || result.hasWarnings()) {
failedResults.put(pool.getId(), result);
log.debug("Pool filtered from candidates due to rules failure: {}", pool.getId());
} else {
filteredPools.add(pool);
}
}
}
// Only throw refused exception if we actually hit the rules:
if (filteredPools.size() == 0 && !failedResults.isEmpty()) {
throw new EntitlementRefusedException(failedResults);
}
List<PoolQuantity> enforced = autobindRules.selectBestPools(consumer, productIds, filteredPools, compliance, serviceLevelOverride, poolCurator.retrieveServiceLevelsForOwner(ownerId, true), false);
// Sort the resulting pools to avoid deadlocks
Collections.sort(enforced);
return enforced;
}
use of org.candlepin.policy.EntitlementRefusedException in project candlepin by candlepin.
the class CandlepinPoolManager method adjustEntitlementQuantity.
@Override
@Transactional
public /*
* NOTE: please refer to the comment on create entitlements with respect to locking.
*/
Entitlement adjustEntitlementQuantity(Consumer consumer, Entitlement entitlement, Integer quantity) throws EntitlementRefusedException {
int change = quantity - entitlement.getQuantity();
if (change == 0) {
return entitlement;
}
// Because there are several paths to this one place where entitlements
// are updated, we cannot be positive the caller obtained a lock on the
// pool when it was read. As such we're going to reload it with a lock
// before starting this process.
log.debug("Updating entitlement, Locking pool: {}", entitlement.getPool().getId());
Pool pool = poolCurator.lockAndLoad(entitlement.getPool());
if (pool == null) {
throw new RuntimeException("Unable to lock pool for entitlement: " + entitlement);
}
log.debug("Locked pool: {} consumed: {}", pool, pool.getConsumed());
ValidationResult result = enforcer.update(consumer, entitlement, change);
if (!result.isSuccessful()) {
log.warn("Entitlement not updated: {} for pool: {}", result.getErrors().toString(), pool.getId());
Map<String, ValidationResult> errorMap = new HashMap<>();
errorMap.put(pool.getId(), result);
throw new EntitlementRefusedException(errorMap);
}
/*
* Grab an exclusive lock on the consumer to prevent deadlock.
*/
consumer = consumerCurator.lockAndLoad(consumer);
ConsumerType ctype = this.consumerTypeCurator.getConsumerType(consumer);
// Persist the entitlement after it has been updated.
log.info("Processing entitlement and persisting.");
entitlement.setQuantity(entitlement.getQuantity() + change);
entitlementCurator.merge(entitlement);
pool.setConsumed(pool.getConsumed() + change);
if (ctype != null && ctype.isManifest()) {
pool.setExported(pool.getExported() + change);
}
poolCurator.merge(pool);
consumer.setEntitlementCount(consumer.getEntitlementCount() + change);
Map<String, Entitlement> entMap = new HashMap<>();
entMap.put(pool.getId(), entitlement);
Map<String, PoolQuantity> poolQuantityMap = new HashMap<>();
poolQuantityMap.put(pool.getId(), new PoolQuantity(pool, change));
Owner owner = ownerCurator.find(consumer.getOwnerId());
// the only thing we do here is decrement bonus pool quantity
enforcer.postEntitlement(this, consumer, owner, entMap, new ArrayList<>(), true, poolQuantityMap);
// we might have changed the bonus pool quantities, revoke ents if needed.
checkBonusPoolQuantities(consumer.getOwnerId(), entMap);
// if shared ents, update shared pool quantity
if (ctype != null && ctype.isType(ConsumerTypeEnum.SHARE)) {
pool.setShared(pool.getShared() + change);
List<Pool> sharedPools = poolCurator.listBySourceEntitlement(entitlement).list();
for (Pool p : sharedPools) {
setPoolQuantity(p, entitlement.getQuantity().longValue());
}
} else {
this.entitlementCurator.markEntitlementsDirty(Arrays.asList(entitlement.getId()));
}
/*
* If the consumer is not a distributor or share, check consumer's new compliance
* status and save. the getStatus call does that internally.
* all consumer's entitlement count are updated though, so we need to update irrespective
* of the consumer type.
*/
complianceRules.getStatus(consumer, null, false, false);
consumerCurator.update(consumer);
poolCurator.flush();
return entitlement;
}
Aggregations