package io.cattle.platform.resource.pool.impl; import static io.cattle.platform.core.model.tables.ResourcePoolTable.*; import io.cattle.platform.core.model.ResourcePool; import io.cattle.platform.object.ObjectManager; import io.cattle.platform.object.util.ObjectUtils; import io.cattle.platform.resource.pool.PooledResource; import io.cattle.platform.resource.pool.PooledResourceItemGenerator; import io.cattle.platform.resource.pool.PooledResourceItemGeneratorFactory; import io.cattle.platform.resource.pool.PooledResourceOptions; import io.cattle.platform.resource.pool.ResourcePoolManager; import io.cattle.platform.util.type.CollectionUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.jooq.exception.DataAccessException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ResourcePoolManagerImpl implements ResourcePoolManager { private static final Logger log = LoggerFactory.getLogger(ResourcePoolManagerImpl.class); ObjectManager objectManager; List<PooledResourceItemGeneratorFactory> factories; @Override public List<PooledResource> allocateResource(Object pool, Object owner, PooledResourceOptions options) { String qualifier = options.getQualifier(); int count = options.getCount(); String poolType = getResourceType(pool); long poolId = getResourceId(pool); String ownerType = getResourceType(owner); long ownerId = getResourceId(owner); Map<Object, Object> keys = CollectionUtils.asMap((Object) RESOURCE_POOL.POOL_TYPE, poolType, (Object) RESOURCE_POOL.POOL_ID, poolId, RESOURCE_POOL.QUALIFIER, qualifier, RESOURCE_POOL.OWNER_TYPE, ownerType, RESOURCE_POOL.OWNER_ID, ownerId); List<ResourcePool> resourcePools = new ArrayList<ResourcePool>(objectManager.find(ResourcePool.class, keys)); List<PooledResource> result = new ArrayList<PooledResource>(); for (ResourcePool resourcePool : resourcePools) { result.add(new DefaultPooledResource(resourcePool.getItem())); } while (result.size() < count) { String item = getItem(keys, pool, qualifier, options.getRequestedItem()); if (item == null) { break; } else { log.info("Assigning [{}] from pool [{}:{}] to owner [{}:{}]", item, poolType, poolId, ownerType, ownerId); } result.add(new DefaultPooledResource(item)); } if (result.size() != count) { log.info("Failed to find [{}] items for pool [{}:{}] and owner [{}:{}]", count, poolType, poolId, ownerType, ownerId); releaseResource(pool, owner, options); return null; } return result; } @Override public void releaseResource(Object pool, Object owner) { releaseResource(pool, owner, new PooledResourceOptions()); } @Override public void releaseResource(Object pool, Object owner, PooledResourceOptions options) { String poolType = getResourceType(pool); long poolId = getResourceId(pool); String ownerType = getResourceType(owner); long ownerId = getResourceId(owner); Map<Object, Object> keys = CollectionUtils.asMap((Object) RESOURCE_POOL.POOL_TYPE, poolType, (Object) RESOURCE_POOL.POOL_ID, poolId, RESOURCE_POOL.QUALIFIER, options.getQualifier(), RESOURCE_POOL.OWNER_TYPE, ownerType, RESOURCE_POOL.OWNER_ID, ownerId); for (ResourcePool resource : objectManager.find(ResourcePool.class, keys)) { log.info("Releasing [{}] id [{}] to pool [{}:{}] from owner [{}:{}]", resource.getItem(), resource.getId(), poolType, poolId, ownerType, ownerId); objectManager.delete(resource); } } @Override public void transferResource(Object pool, Object owner, Object newOwner) { transferResource(pool, owner, newOwner, new PooledResourceOptions()); } @Override public void transferResource(Object pool, Object owner, Object newOwner, PooledResourceOptions options) { String poolType = getResourceType(pool); long poolId = getResourceId(pool); String ownerType = getResourceType(owner); long ownerId = getResourceId(owner); String newOwnerType = getResourceType(newOwner); long newOwnerId = getResourceId(newOwner); Map<Object, Object> keys = CollectionUtils.asMap((Object) RESOURCE_POOL.POOL_TYPE, poolType, (Object) RESOURCE_POOL.POOL_ID, poolId, RESOURCE_POOL.QUALIFIER, options.getQualifier(), RESOURCE_POOL.OWNER_TYPE, ownerType, RESOURCE_POOL.OWNER_ID, ownerId); for (ResourcePool resource : objectManager.find(ResourcePool.class, keys)) { log.info("Transfering [{}] id [{}] from pool [{}:{}] from owner [{}:{}] to owner [{}:{}]", resource.getItem(), resource.getId(), poolType, poolId, ownerType, ownerId, newOwnerType, newOwnerId); resource.setOwnerType(newOwnerType); resource.setOwnerId(newOwnerId); objectManager.persist(resource); } } @Override public PooledResource allocateOneResource(Object pool, Object owner, PooledResourceOptions options) { List<PooledResource> resources = allocateResource(pool, owner, options); return (resources == null || resources.size() == 0) ? null : resources.get(0); } protected String getItem(Map<Object, Object> keys, Object pool, String qualifier, String tryItem) { PooledResourceItemGenerator generator = null; for (PooledResourceItemGeneratorFactory factory : factories) { generator = factory.getGenerator(pool, qualifier); if (generator != null) { break; } } if (generator == null) { log.error("Failed to find generator for pool [{}]", pool); return null; } while (generator.hasNext()) { String item = null; if (tryItem == null) { item = generator.next(); } else { item = generator.isInPool(tryItem) ? tryItem : generator.next(); tryItem = null; } Map<Object, Object> newKeys = new HashMap<Object, Object>(keys); newKeys.put(RESOURCE_POOL.ITEM, item); Map<String, Object> props = objectManager.convertToPropertiesFor(ResourcePool.class, newKeys); try { return objectManager.create(ResourcePool.class, props).getItem(); } catch (DataAccessException e) { log.debug("Failed to create item [{}]", item); } } return null; } protected String getResourceType(Object obj) { if (GLOBAL.equals(obj)) { return GLOBAL; } String type = objectManager.getType(obj); if (type == null) { throw new IllegalStateException("Failed to find resource type for [" + obj + "]"); } return type; } protected long getResourceId(Object obj) { if (GLOBAL.equals(obj)) { return 1; } Object id = ObjectUtils.getId(obj); if (id instanceof Number) { return ((Number) id).longValue(); } throw new IllegalStateException("Failed to find resource id for [" + obj + "]"); } public ObjectManager getObjectManager() { return objectManager; } @Inject public void setObjectManager(ObjectManager objectManager) { this.objectManager = objectManager; } public List<PooledResourceItemGeneratorFactory> getFactories() { return factories; } @Inject public void setFactories(List<PooledResourceItemGeneratorFactory> factories) { this.factories = factories; } }