use of org.candlepin.model.dto.Subscription in project candlepin by candlepin.
the class CandlepinPoolManager method refreshPoolsWithRegeneration.
/*
* We need to update/regen entitlements in the same transaction we update pools
* so we don't miss anything
*/
@Transactional
@SuppressWarnings("checkstyle:methodlength")
@Traceable
void refreshPoolsWithRegeneration(SubscriptionServiceAdapter subAdapter, @TraceableParam("owner") Owner owner, boolean lazy) {
Date now = new Date();
owner = this.resolveOwner(owner);
log.info("Refreshing pools for owner: {}", owner);
Map<String, Subscription> subscriptionMap = new HashMap<>();
Map<String, ProductData> productMap = new HashMap<>();
Map<String, ContentData> contentMap = new HashMap<>();
// Resolve all our subscriptions, products and content to ensure we don't have bad or
// duplicate inbound data
log.debug("Fetching subscriptions from adapter...");
List<Subscription> subscriptions = subAdapter.getSubscriptions(owner);
log.debug("Done. Processing subscriptions...");
for (Subscription subscription : subscriptions) {
if (subscription == null) {
continue;
}
if (subscription.getId() == null) {
log.error("subscription does not contain a mappable ID: {}", subscription);
throw new IllegalStateException("subscription does not contain a mappable ID: " + subscription);
}
Subscription existingSub = subscriptionMap.get(subscription.getId());
if (existingSub != null && !existingSub.equals(subscription)) {
log.warn("Multiple versions of the same subscription received during refresh; " + "discarding duplicate: {} => {}, {}", subscription.getId(), existingSub, subscription);
continue;
}
subscriptionMap.put(subscription.getId(), subscription);
List<ProductData> products = new LinkedList<>();
products.add(subscription.getProduct());
products.add(subscription.getDerivedProduct());
products.addAll(subscription.getProvidedProducts());
products.addAll(subscription.getDerivedProvidedProducts());
for (ProductData product : products) {
if (product == null) {
// forward.
continue;
}
if (product.getId() == null) {
log.error("product does not contain a mappable Red Hat ID: {}", product);
throw new IllegalStateException("product does not contain a mappable Red Hat ID: " + product);
}
// Product is coming from an upstream source; lock it so only upstream can make
// further changes to it.
product.setLocked(true);
ProductData existingProduct = productMap.get(product.getId());
if (existingProduct != null && !existingProduct.equals(product)) {
log.warn("Multiple versions of the same product received during refresh; " + "discarding duplicate: {} => {}, {}", product.getId(), existingProduct, product);
} else {
productMap.put(product.getId(), product);
Collection<ProductContentData> pcdCollection = product.getProductContent();
if (pcdCollection != null) {
for (ProductContentData pcd : pcdCollection) {
if (pcd == null) {
log.error("product contains a null product-content mapping: {}", product);
throw new IllegalStateException("product contains a null product-content mapping: " + product);
}
ContentData content = pcd.getContent();
// population validation for us.
if (content == null || content.getId() == null) {
log.error("product contains a null or incomplete product-content mapping: {}", product);
throw new IllegalStateException("product contains a null or incomplete " + "product-content mapping: " + product);
}
// We need to lock the incoming content here, but doing so will affect
// the equality comparison for products. We'll correct them later.
ContentData existingContent = contentMap.get(content.getId());
if (existingContent != null && !existingContent.equals(content)) {
log.warn("Multiple versions of the same content received during refresh; " + "discarding duplicate: {} => {}, {}", content.getId(), existingContent, content);
} else {
contentMap.put(content.getId(), content);
}
}
}
}
}
}
// Persist content changes
log.debug("Importing {} content...", contentMap.size());
// TODO: Find a more efficient way of doing this, preferably within this method
for (ContentData cdata : contentMap.values()) {
cdata.setLocked(true);
}
Map<String, Content> importedContent = this.contentManager.importContent(owner, contentMap, productMap.keySet()).getImportedEntities();
log.debug("Importing {} product(s)...", productMap.size());
ImportResult<Product> importResult = this.productManager.importProducts(owner, productMap, importedContent);
Map<String, Product> importedProducts = importResult.getImportedEntities();
Map<String, Product> updatedProducts = importResult.getUpdatedEntities();
log.debug("Refreshing {} pool(s)...", subscriptionMap.size());
Iterator<Map.Entry<String, Subscription>> subsIterator = subscriptionMap.entrySet().iterator();
while (subsIterator.hasNext()) {
Map.Entry<String, Subscription> entry = subsIterator.next();
Subscription sub = entry.getValue();
if (now.after(sub.getEndDate())) {
log.info("Skipping expired subscription: {}", sub);
subsIterator.remove();
continue;
}
log.debug("Processing subscription: {}", sub);
Pool pool = this.convertToMasterPoolImpl(sub, owner, importedProducts);
this.refreshPoolsForMasterPool(pool, false, lazy, updatedProducts);
}
// delete pools whose subscription disappeared:
log.debug("Deleting pools for absent subscriptions...");
List<Pool> poolsToDelete = new ArrayList<>();
for (Pool pool : poolCurator.getPoolsFromBadSubs(owner, subscriptionMap.keySet())) {
if (this.isManaged(pool)) {
poolsToDelete.add(pool);
}
}
deletePools(poolsToDelete);
// TODO: break this call into smaller pieces. There may be lots of floating pools
log.debug("Updating floating pools...");
List<Pool> floatingPools = poolCurator.getOwnersFloatingPools(owner);
updateFloatingPools(floatingPools, lazy, updatedProducts);
log.info("Refresh pools for owner: {} completed in: {}ms", owner.getKey(), System.currentTimeMillis() - now.getTime());
}
use of org.candlepin.model.dto.Subscription in project candlepin by candlepin.
the class Refresher method run.
public void run() {
// If products were specified on the refresher, lookup any subscriptions
// using them, regardless of organization, and trigger a refresh for those
// specific subscriptions.
Set<Subscription> subscriptions = new HashSet<>();
for (Product product : products) {
// TODO: This adapter call is not implemented in prod, and cannot be. We plan
// to fix this whole code path in near future by looking for pools using the
// given products to be refreshed.
List<Subscription> subs = subAdapter.getSubscriptions(product.toDTO());
log.debug("Will refresh {} subscriptions in all orgs using product: ", subs.size(), product.getId());
if (log.isDebugEnabled()) {
for (Subscription s : subs) {
Owner so = s.getOwner();
if (so == null || so.getKey() == null) {
log.debug(" Received a subscription without a well-defined owner: {}", s.getId());
continue;
}
if (!this.owners.containsKey(so.getKey())) {
log.debug(" {}", s);
}
}
}
subscriptions.addAll(subs);
}
for (Subscription subscription : subscriptions) {
// drop any subs for owners in our owners list. we'll get them with the full
// refreshPools call.
Owner so = subscription.getOwner();
// This probably shouldn't ever happen, but let's make sure it doesn't anyway.
if (so == null || so.getKey() == null) {
log.error("Received a subscription without a well-defined owner: {}", subscription.getId());
continue;
}
if (this.owners.containsKey(so.getKey())) {
log.debug("Skipping subscription \"{}\" for owner: {}", subscription.getId(), so);
continue;
}
/*
* on the off chance that this is actually a new subscription, make
* the required pools. this shouldn't happen; we should really get a
* refresh pools by owner call for it, but why not handle it, just
* in case!
*
* Regenerate certificates here, that way if it fails, the whole
* thing rolls back. We don't want to refresh without marking ents
* dirty, they will never get regenerated
*/
Pool masterPool = poolManager.convertToMasterPool(subscription);
poolManager.refreshPoolsForMasterPool(masterPool, true, lazy, Collections.<String, Product>emptyMap());
}
for (Owner owner : this.owners.values()) {
poolManager.refreshPoolsWithRegeneration(this.subAdapter, owner, this.lazy);
poolManager.recalculatePoolQuantitiesForOwner(owner);
ownerManager.refreshContentAccessMode(this.ownerAdapter, owner);
ownerManager.updateRefreshDate(owner);
}
}
use of org.candlepin.model.dto.Subscription in project candlepin by candlepin.
the class SubscriptionReconcilerTest method testQuantMatchAllLower.
@Test
public void testQuantMatchAllLower() {
Subscription testSub1 = createSubscription(owner, "test-prod-1", "up1", "ue1", "uc1", 25);
Subscription testSub2 = createSubscription(owner, "test-prod-1", "up1", "ue2", "uc1", 20);
Subscription testSub3 = createSubscription(owner, "test-prod-1", "up1", "ue3", "uc1", 15);
Subscription testSub12 = createSubscription(owner, "test-prod-1", "up1", "ue12", "uc3", 23);
Subscription testSub13 = createSubscription(owner, "test-prod-1", "up1", "ue13", "uc3", 17);
Subscription testSub14 = createSubscription(owner, "test-prod-1", "up1", "ue14", "uc3", 10);
createPoolsFor(testSub1, testSub2, testSub3);
reconciler.reconcile(owner, Arrays.asList(testSub12, testSub13, testSub14));
// Quantities 25, 20, 15 should be replaced by new pools with 23, 17, 10:
assertUpstream(testSub12, testSub1.getId());
assertUpstream(testSub13, testSub2.getId());
assertUpstream(testSub14, testSub3.getId());
}
use of org.candlepin.model.dto.Subscription in project candlepin by candlepin.
the class SubscriptionReconcilerTest method createSubscription.
private Subscription createSubscription(Owner daOwner, String productId, String poolId, String entId, String conId, long quantity) {
ProductData pdata = new ProductData();
pdata.setId(productId);
pdata.setName(productId);
Subscription sub = new Subscription();
sub.setProduct(pdata);
sub.setUpstreamPoolId(poolId);
sub.setUpstreamEntitlementId(entId);
sub.setUpstreamConsumerId(conId);
sub.setQuantity(quantity);
sub.setOwner(daOwner);
sub.setId("" + index++);
return sub;
}
use of org.candlepin.model.dto.Subscription in project candlepin by candlepin.
the class SubscriptionReconcilerTest method oneExistsOneNew.
@Test
public void oneExistsOneNew() {
Subscription testSub2 = createSubscription(owner, "test-prod-1", "up1", "ue2", "uc1", 20);
Subscription testSub3 = createSubscription(owner, "test-prod-1", "up1", "ue3", "uc1", 15);
createPoolsFor(testSub2);
reconciler.reconcile(owner, Arrays.asList(testSub2, testSub3));
assertUpstream(testSub2, testSub2.getId());
assertUpstream(testSub3, testSub3.getId());
}
Aggregations