use of org.candlepin.policy.ValidationResult in project candlepin by candlepin.
the class EntitlementRules method filterPools.
@Override
@SuppressWarnings("checkstyle:indentation")
public List<Pool> filterPools(Consumer consumer, List<Pool> pools, boolean showAll) {
JsonJsContext args = new JsonJsContext(objectMapper);
Map<String, ValidationResult> resultMap = new HashMap<>();
ConsumerType ctype = this.consumerTypeCurator.getConsumerType(consumer);
if (!ctype.isType(ConsumerTypeEnum.SHARE)) {
Stream<PoolDTO> poolStream = pools == null ? Stream.empty() : pools.stream().map(this.translator.getStreamMapper(Pool.class, PoolDTO.class));
Stream<EntitlementDTO> entStream = consumer.getEntitlements() == null ? Stream.empty() : consumer.getEntitlements().stream().map(this.translator.getStreamMapper(Entitlement.class, EntitlementDTO.class));
args.put("consumer", this.translator.translate(consumer, ConsumerDTO.class));
args.put("hostConsumer", this.translator.translate(getHost(consumer, pools), ConsumerDTO.class));
args.put("consumerEntitlements", entStream.collect(Collectors.toSet()));
args.put("standalone", config.getBoolean(ConfigProperties.STANDALONE));
args.put("pools", poolStream.collect(Collectors.toSet()));
args.put("caller", CallerType.LIST_POOLS.getLabel());
args.put("log", log, false);
String json = jsRules.runJsFunction(String.class, "validate_pools_list", args);
TypeReference<Map<String, ValidationResult>> typeref = new TypeReference<Map<String, ValidationResult>>() {
};
try {
resultMap = objectMapper.toObject(json, typeref);
} catch (Exception e) {
throw new RuleExecutionException(e);
}
}
List<Pool> filteredPools = new LinkedList<>();
for (Pool pool : pools) {
ValidationResult result;
if (ctype.isType(ConsumerTypeEnum.SHARE)) {
result = new ValidationResult();
resultMap.put(pool.getId(), result);
validatePoolSharingEligibility(result, pool);
} else {
result = resultMap.get(pool.getId());
}
finishValidation(result, pool, 1);
if (result.isSuccessful() && (!result.hasWarnings() || showAll)) {
filteredPools.add(pool);
} else if (log.isDebugEnabled()) {
log.debug("Omitting pool due to failed rules: " + pool.getId());
if (result.hasErrors()) {
log.debug("\tErrors: " + result.getErrors());
}
if (result.hasWarnings()) {
log.debug("\tWarnings: " + result.getWarnings());
}
}
}
return filteredPools;
}
use of org.candlepin.policy.ValidationResult 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.ValidationResult 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;
}
use of org.candlepin.policy.ValidationResult in project candlepin by candlepin.
the class PreEntitlementRulesCheckOp method checkResults.
private EntitlementRefusedException checkResults() {
boolean success = true;
for (Map.Entry<String, ValidationResult> entry : results.entrySet()) {
ValidationResult result = entry.getValue();
if (!result.isSuccessful()) {
log.warn("Entitlement not granted: {} for pool: {}", result.getErrors().toString(), entry.getKey());
success = false;
}
}
if (!success) {
return new EntitlementRefusedException(results);
}
return null;
}
use of org.candlepin.policy.ValidationResult in project candlepin by candlepin.
the class ManifestEntitlementRulesTest method preEntitlementShouldNotAllowListOfDerivedPools.
@Test
public void preEntitlementShouldNotAllowListOfDerivedPools() {
Consumer c = this.createMockConsumer(true);
Product prod = TestUtil.createProduct();
Pool p = TestUtil.createPool(prod);
p.setAttribute(Product.Attributes.VIRT_ONLY, "true");
p.setAttribute(Pool.Attributes.DERIVED_POOL, "true");
p.setId("poolId");
ValidationResult results = enforcer.preEntitlement(c, p, 1, CallerType.LIST_POOLS);
assertNotNull(results);
assertEquals(1, results.getErrors().size());
ValidationError error = results.getErrors().get(0);
assertEquals("pool.not.available.to.manifest.consumers", error.getResourceKey());
}
Aggregations