Search in sources :

Example 6 with Owner

use of org.candlepin.model.Owner in project candlepin by candlepin.

the class ResolverUtil method resolvePool.

public Pool resolvePool(Pool pool) {
    // doesn't (i.e. during creation). We just need to make sure it's not null.
    if (pool == null) {
        throw new BadRequestException(i18n.tr("No subscription specified"));
    }
    // Ensure the owner is set and is valid
    Owner owner = this.resolveOwner(pool.getOwner());
    pool.setOwner(owner);
    // Ensure the specified product(s) exists for the given owner
    pool.setProduct(this.resolveProduct(owner, pool.getProduct()));
    if (pool.getDerivedProduct() != null) {
        pool.setDerivedProduct(this.resolveProduct(owner, pool.getDerivedProduct()));
    }
    HashSet<Product> presolved = new HashSet<>();
    pool.populateAllTransientProvidedProducts(productCurator);
    for (ProvidedProduct product : pool.getProvidedProductDtos()) {
        // TODO: Maybe add UUID resolution as well?
        presolved.add(resolveProduct(owner, product.getProductId()));
    }
    pool.setProvidedProducts(presolved);
    presolved.clear();
    for (ProvidedProduct product : pool.getDerivedProvidedProductDtos()) {
        presolved.add(this.resolveProduct(owner, product.getProductId()));
    }
    pool.setDerivedProvidedProducts(presolved);
    return pool;
}
Also used : Owner(org.candlepin.model.Owner) BadRequestException(org.candlepin.common.exceptions.BadRequestException) ProvidedProduct(org.candlepin.model.ProvidedProduct) Product(org.candlepin.model.Product) ProvidedProduct(org.candlepin.model.ProvidedProduct) HashSet(java.util.HashSet)

Example 7 with Owner

use of org.candlepin.model.Owner in project candlepin by candlepin.

the class CandlepinPoolManager method deletePools.

@Override
@Transactional
@Traceable
@SuppressWarnings("checkstyle:methodlength")
public void deletePools(Collection<Pool> pools, Collection<String> alreadyDeletedPoolIds) {
    if (pools == null || pools.isEmpty()) {
        return;
    }
    log.info("Attempting to delete {} pools...", pools.size());
    // than they need to be and is resulting in running slow calculations multiple times.
    if (alreadyDeletedPoolIds == null) {
        alreadyDeletedPoolIds = new HashSet<>();
    }
    Set<String> poolIds = new HashSet<>();
    Set<String> entitlementIds = new HashSet<>();
    Owner owner = null;
    // Convert pools to pool IDs.
    log.info("Fetching related pools and entitlements...");
    for (Pool pool : pools) {
        if (owner == null) {
            owner = pool.getOwner();
        }
        poolIds.add(pool.getId());
    }
    // Fetch pools which are derived from the pools we're going to delete...
    poolIds.addAll(this.poolCurator.getDerivedPoolIdsForPools(poolIds));
    // Fetch related pools and entitlements (recursively)
    Collection<String> pids = poolIds;
    int cachedSize;
    do {
        // Fetch entitlement IDs for our set of pools
        Collection<String> eids = this.poolCurator.getEntitlementIdsForPools(pids);
        // Fetch pools which are derived from these entitlements...
        pids = this.poolCurator.getPoolIdsForSourceEntitlements(eids);
        // Fetch stack derived pools which will be unentitled when we revoke entitlements
        // Impl note: This may occassionally miss stack derived pools in cases where our
        // entitlement count exceeds the IN block limitations. In those cases, we'll end
        // up doing a recursive call into this method, which sucks, but will still work.
        pids.addAll(this.poolCurator.getUnentitledStackDerivedPoolIds(eids));
        // Fetch pools which are derived from the pools we're going to delete...
        pids.addAll(this.poolCurator.getDerivedPoolIdsForPools(pids));
        // Add the new entitlement and pool IDs to our list of things to delete
        cachedSize = poolIds.size();
        entitlementIds.addAll(eids);
        poolIds.addAll(pids);
    } while (poolIds.size() != cachedSize);
    // TODO: Remove this and stop recursively calling into this method.
    if (alreadyDeletedPoolIds != null) {
        poolIds.removeAll(alreadyDeletedPoolIds);
    }
    // Lock pools we're going to delete (also, fetch them for event generation/slow deletes)
    pools = this.poolCurator.lockAndLoadByIds(poolIds);
    if (!pools.isEmpty()) {
        log.info("Locked {} pools for deletion...", pools.size());
        // Impl note:
        // There is a fair bit of duplicated work between the actions below this block and
        // methods like revokeEntitlements. However, the decision was made to decouple these
        // methods explicitly to avoid situations such as fetching collections of pools, getting
        // entitlements from them (a slow process in itself) and then passing it off to another
        // standalone method which repeats the process of fetching pools and related entitlements.
        // 
        // More work can be done in revokeEntitlements to optimize that method and maybe make it
        // slightly more generic so that this work can be offloaded to it again. Though, at the time
        // of writing, that's no small undertaking. Even changing this method has far-reaching
        // consequences when trying to remove direct uses of entities as far as interoperability is
        // concerned. Going forward we need to be more aware of the amount of duplication we're
        // adding to our code when writing standlone/generic utility methods and linking them
        // together, and perhaps take steps to avoid getting into situations like these two methods.
        // Fetch the list of pools which are related to the entitlements but are *not* being
        // deleted. We'll need to update the quantities on these.
        Collection<String> affectedPoolIds = this.poolCurator.getPoolIdsForEntitlements(entitlementIds);
        affectedPoolIds.removeAll(poolIds);
        // Fetch entitlements (uggh).
        // TODO: Stop doing this. Update the bits below to not use the entities directly and
        // do the updates via queries.
        Collection<Entitlement> entitlements = !entitlementIds.isEmpty() ? this.entitlementCurator.listAllByIds(entitlementIds).list() : Collections.<Entitlement>emptySet();
        // Mark remaining dependent entitlements dirty for this consumer
        this.entitlementCurator.markDependentEntitlementsDirty(entitlementIds);
        // Unlink the pools and entitlements we're about to delete so we don't error out while
        // trying to delete entitlements.
        this.poolCurator.clearPoolSourceEntitlementRefs(poolIds);
        // Revoke/delete entitlements
        if (!entitlements.isEmpty()) {
            log.info("Revoking {} entitlements...", entitlements.size());
            this.entitlementCurator.batchDelete(entitlements);
            this.entitlementCurator.flush();
            log.info("Entitlements successfully revoked");
        } else {
            log.info("Skipping entitlement revocation; no entitlements to revoke");
        }
        // Delete pools
        log.info("Deleting {} pools...", pools.size());
        this.poolCurator.batchDelete(pools, alreadyDeletedPoolIds);
        this.poolCurator.flush();
        log.info("Pools successfully deleted");
        if (!entitlements.isEmpty()) {
            // Update entitlement counts on affected, non-deleted pools
            log.info("Updating entitlement counts on remaining, affected pools...");
            Map<Consumer, List<Entitlement>> consumerStackedEnts = new HashMap<>();
            List<Pool> poolsToSave = new LinkedList<>();
            Set<String> stackIds = new HashSet<>();
            for (Entitlement entitlement : entitlements) {
                // Since we're sifting through these already, let's also sort them into consumer lists
                // for some of the other methods we'll be calling later
                Consumer consumer = entitlement.getConsumer();
                Pool pool = entitlement.getPool();
                List<Entitlement> stackedEntitlements = consumerStackedEnts.get(consumer);
                if (stackedEntitlements == null) {
                    stackedEntitlements = new LinkedList<>();
                    consumerStackedEnts.put(consumer, stackedEntitlements);
                }
                if (!"true".equals(pool.getAttributeValue(Pool.Attributes.DERIVED_POOL)) && pool.hasProductAttribute(Product.Attributes.STACKING_ID)) {
                    stackedEntitlements.add(entitlement);
                    stackIds.add(entitlement.getPool().getStackId());
                }
                // Update quantities if the entitlement quantity is non-zero
                int quantity = entitlement.getQuantity() != null ? entitlement.getQuantity() : 0;
                if (quantity != 0) {
                    // Update the pool quantities if we didn't delete it
                    if (affectedPoolIds.contains(pool.getId())) {
                        pool.setConsumed(pool.getConsumed() - quantity);
                        poolsToSave.add(pool);
                    }
                    // Update entitlement counts for affected consumers...
                    consumer.setEntitlementCount(consumer.getEntitlementCount() - quantity);
                    // Set the number exported if we're working with a manifest distributor
                    ConsumerType ctype = this.consumerTypeCurator.getConsumerType(consumer);
                    if (ctype != null && ctype.isManifest()) {
                        pool.setExported(pool.getExported() - quantity);
                    }
                }
            }
            this.poolCurator.updateAll(poolsToSave, false, false);
            this.consumerCurator.updateAll(consumerStackedEnts.keySet(), false, false);
            this.consumerCurator.flush();
            log.info("Entitlement counts successfully updated for {} pools and {} consumers", poolsToSave.size(), consumerStackedEnts.size());
            // Update stacked entitlements for affected consumers(???)
            if (!stackIds.isEmpty()) {
                // Get consumer + pool tuples for stack ids
                Map<String, Set<String>> consumerStackDerivedPoolIds = this.poolCurator.getConsumerStackDerivedPoolIdMap(stackIds);
                if (!consumerStackDerivedPoolIds.isEmpty()) {
                    log.info("Updating stacked entitlements for {} consumers...", consumerStackDerivedPoolIds.size());
                    for (Consumer consumer : consumerStackedEnts.keySet()) {
                        Set<String> subPoolIds = consumerStackDerivedPoolIds.get(consumer.getId());
                        if (subPoolIds != null && !subPoolIds.isEmpty()) {
                            // Resolve pool IDs...
                            Collection<Pool> subPools = this.poolCurator.listAllByIds(subPoolIds).list();
                            // Invoke the rules engine to update the affected pools
                            if (subPools != null && !subPools.isEmpty()) {
                                log.debug("Updating {} stacking pools for consumer: {}", subPools.size(), consumer);
                                this.poolRules.updatePoolsFromStack(consumer, subPools, alreadyDeletedPoolIds, true);
                            }
                        }
                    }
                }
            }
            this.consumerCurator.flush();
            // Hydrate remaining consumer pools so we can skip some extra work during serialization
            Set<Pool> poolsToHydrate = new HashSet<>();
            for (Consumer consumer : consumerStackedEnts.keySet()) {
                for (Entitlement entitlement : consumer.getEntitlements()) {
                    poolsToHydrate.add(entitlement.getPool());
                }
            }
            this.productCurator.hydratePoolProvidedProducts(poolsToHydrate);
            // Fire post-unbind events for revoked entitlements
            log.info("Firing post-unbind events for {} entitlements...", entitlements.size());
            for (Entitlement entitlement : entitlements) {
                this.enforcer.postUnbind(entitlement.getConsumer(), this, entitlement);
            }
            // Recalculate status for affected consumers
            log.info("Recomputing status for {} consumers", consumerStackedEnts.size());
            int i = 0;
            for (Consumer consumer : consumerStackedEnts.keySet()) {
                this.complianceRules.getStatus(consumer);
                if (++i % 1000 == 0) {
                    this.consumerCurator.flush();
                }
            }
            this.consumerCurator.flush();
            log.info("All statuses recomputed");
        }
        // Impl note:
        // We don't need to fire entitlement revocation events, since they're all being revoked as
        // a consequence of the pools being deleted.
        // Fire pool deletion events
        // This part hurts so much. Because we output the whole entity, we have to fetch the bloody
        // things before we delete them.
        log.info("Firing pool deletion events for {} pools...", pools.size());
        for (Pool pool : pools) {
            this.sink.queueEvent(this.eventFactory.poolDeleted(pool));
        }
    } else {
        log.info("Skipping pool deletion; no pools to delete");
    }
}
Also used : Owner(org.candlepin.model.Owner) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) LinkedList(java.util.LinkedList) Consumer(org.candlepin.model.Consumer) Pool(org.candlepin.model.Pool) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Entitlement(org.candlepin.model.Entitlement) ConsumerType(org.candlepin.model.ConsumerType) HashSet(java.util.HashSet) Traceable(org.candlepin.util.Traceable) Transactional(com.google.inject.persist.Transactional)

Example 8 with Owner

use of org.candlepin.model.Owner in project candlepin by candlepin.

the class CandlepinPoolManager method convertToMasterPool.

/*
     * if you are using this method, you might want to override the quantity
     * with PoolRules.calculateQuantity
     */
@Override
public Pool convertToMasterPool(Subscription sub) {
    if (sub == null) {
        throw new IllegalArgumentException("subscription is null");
    }
    // Resolve the subscription's owner...
    if (sub.getOwner() == null || (sub.getOwner().getId() == null && sub.getOwner().getKey() == null)) {
        throw new IllegalStateException("Subscription references an invalid owner: " + sub.getOwner());
    }
    Owner owner = sub.getOwner().getId() != null ? this.ownerCurator.find(sub.getOwner().getId()) : this.ownerCurator.lookupByKey(sub.getOwner().getKey());
    if (owner == null) {
        throw new IllegalStateException("Subscription references an owner which cannot be resolved: " + sub.getOwner());
    }
    // Gather the product IDs referenced by this subscription...
    Set<ProductData> productData = new HashSet<>();
    Set<String> productIds = new HashSet<>();
    Map<String, Product> productMap = new HashMap<>();
    productData.add(sub.getProduct());
    productData.add(sub.getDerivedProduct());
    if (sub.getProvidedProducts() != null) {
        productData.addAll(sub.getProvidedProducts());
    }
    if (sub.getDerivedProvidedProducts() != null) {
        productData.addAll(sub.getDerivedProvidedProducts());
    }
    for (ProductData pdata : productData) {
        if (pdata != null) {
            if (pdata.getId() == null) {
                throw new IllegalStateException("Subscription references an incomplete product: " + pdata);
            }
            productIds.add(pdata.getId());
        }
    }
    // Build the product map from the product IDs we pulled off the subscription...
    for (Product product : this.ownerProductCurator.getProductsByIds(owner, productIds)) {
        productMap.put(product.getId(), product);
    }
    return this.convertToMasterPoolImpl(sub, owner, productMap);
}
Also used : ProductData(org.candlepin.model.dto.ProductData) Owner(org.candlepin.model.Owner) HashMap(java.util.HashMap) Product(org.candlepin.model.Product) HashSet(java.util.HashSet)

Example 9 with Owner

use of org.candlepin.model.Owner 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 10 with Owner

use of org.candlepin.model.Owner 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);
    }
}
Also used : Owner(org.candlepin.model.Owner) Product(org.candlepin.model.Product) Pool(org.candlepin.model.Pool) Subscription(org.candlepin.model.dto.Subscription) HashSet(java.util.HashSet)

Aggregations

Owner (org.candlepin.model.Owner)405 Test (org.junit.Test)254 Product (org.candlepin.model.Product)153 Consumer (org.candlepin.model.Consumer)127 Pool (org.candlepin.model.Pool)79 Date (java.util.Date)72 ConsumerInstalledProduct (org.candlepin.model.ConsumerInstalledProduct)71 ArrayList (java.util.ArrayList)58 Produces (javax.ws.rs.Produces)52 ConsumerType (org.candlepin.model.ConsumerType)52 ApiOperation (io.swagger.annotations.ApiOperation)50 HashSet (java.util.HashSet)44 Entitlement (org.candlepin.model.Entitlement)44 Path (javax.ws.rs.Path)42 HashMap (java.util.HashMap)41 ApiResponses (io.swagger.annotations.ApiResponses)40 Content (org.candlepin.model.Content)39 BadRequestException (org.candlepin.common.exceptions.BadRequestException)37 Subscription (org.candlepin.model.dto.Subscription)32 List (java.util.List)29