use of org.candlepin.model.PoolQuantity 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.model.PoolQuantity in project candlepin by candlepin.
the class EntitlementCertificateGenerator method generateEntitlementCertificate.
/**
* Generates a new entitlement certificate for the given entitlement and pool.
*
* @param pool
* The pool for which to generate an entitlement certificate
*
* @param entitlement
* The entitlement to use when generating the certificate
*
* @return
* The newly generate entitlement certificate
*/
@Transactional
public EntitlementCertificate generateEntitlementCertificate(Pool pool, Entitlement entitlement) {
Map<String, Product> products = new HashMap<>();
Map<String, Entitlement> entitlements = new HashMap<>();
Map<String, PoolQuantity> poolQuantities = new HashMap<>();
products.put(pool.getId(), pool.getProduct());
entitlements.put(pool.getId(), entitlement);
poolQuantities.put(pool.getId(), new PoolQuantity(pool, entitlement.getQuantity()));
return this.generateEntitlementCertificates(entitlement.getConsumer(), products, poolQuantities, entitlements, true).get(pool.getId());
}
use of org.candlepin.model.PoolQuantity 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.model.PoolQuantity 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.model.PoolQuantity in project candlepin by candlepin.
the class HandleEntitlementsOp method execute.
/**
* associates the pools, consumers with entitlements, and persists the entities as needed.
* also computes all the consumed counts.
* @param context
*/
@Override
public boolean execute(BindContext context) {
Consumer consumer = context.getLockedConsumer();
ConsumerType ctype = context.getConsumerType();
Map<String, Entitlement> entitlementMap = context.getEntitlementMap();
Map<String, PoolQuantity> lockedPools = context.getPoolQuantities();
List<Pool> poolsToSave = new LinkedList<>();
for (Entry<String, PoolQuantity> entry : lockedPools.entrySet()) {
Entitlement ent = entitlementMap.get(entry.getKey());
Pool pool = entry.getValue().getPool();
Integer quantity = ent.getQuantity();
pool.getEntitlements().add(ent);
ent.setPool(pool);
ent.setConsumer(consumer);
ent.setOwner(pool.getOwner());
pool.setConsumed(pool.getConsumed() + quantity);
if (ctype.isManifest()) {
pool.setExported(pool.getExported() + quantity);
} else if (ctype.isType(ConsumerTypeEnum.SHARE)) {
pool.setShared(pool.getShared() + quantity);
}
consumer.addEntitlement(ent);
consumer.setEntitlementCount(consumer.getEntitlementCount() + quantity);
poolsToSave.add(pool);
}
entitlementCurator.saveAll(entitlementMap.values(), false, false);
poolCurator.updateAll(poolsToSave, false, false);
return true;
}
Aggregations