* @throws ProvisionException If there are errors obtaining available disk space. Note this will only
* happen if the {@code ProvisionRequest} contains downloadable {@code PlatformCapability} components and there
* is a problem obtaining the size of the download.
*/
public boolean canProvision(final ProvisionRequest provisionRequest) throws ProvisionException {
ServiceElement sElem = provisionRequest.getServiceElement();
if(sElem.getPlanned()==0)
return(false);
String provType = sElem.getProvisionType().toString();
/*
* Check if the serviceLimit has been reached
*/
if(getServiceElementCount() == serviceLimit.get() &&
!provType.equals(ServiceElement.ProvisionType.FIXED.toString())) {
String failureReason =
String.format("%s not selected to allocate service [%s], it has reached it's service limit of [%d]",
getName(), LoggingUtil.getLoggingName(sElem), serviceLimit.get());
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return(false);
}
/*
* Check if the maximum amount per machine has been reached
*/
if(sElem.getMaxPerMachine()!=-1) {
int serviceCount = getServiceElementCount(sElem);
int inProcessCount = getInProcessCounter(sElem);
int numInstances = serviceCount+inProcessCount;
if(numInstances >= sElem.getMaxPerMachine()) {
String failureReason =
String.format("%s not selected to allocate service [%s], declaration specifies no more than %d services per machine, found %d",
getName(), LoggingUtil.getLoggingName(sElem), sElem.getMaxPerMachine(), numInstances);
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return(false);
}
}
/*
* Fixed service allocation is similar to maxPerMachine, ensure that
* there are not too many service allocated
*/
if(sElem.getProvisionType() == ServiceElement.ProvisionType.FIXED) {
int planned = sElem.getPlanned();
int actual = getServiceElementCount(sElem);
int numAllowed = planned-actual;
if(numAllowed <=0) {
String failureReason =
String.format("Do not allocate %s service [%s] to %s has [%d] instance(s), planned [%d]",
provType, LoggingUtil.getLoggingName(sElem), getName(), actual, planned);
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return(false);
} else {
String failureReason =
String.format("%s has [%d] instance(s), planned [%d] of %s service [%s]",
getName(), actual, planned, provType, LoggingUtil.getLoggingName(sElem));
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
}
}
if(!AssociationMatcher.meetsColocationRequirements(sElem, this)) {
StringBuilder b = new StringBuilder();
b.append(getName()).append(" not selected to allocate ").append(LoggingUtil.getLoggingName(sElem));
b.append(", required colocated services not present: ");
AssociationDescriptor[] aDesc = ServiceElementUtil.getAssociationDescriptors(sElem, AssociationType.COLOCATED);
int found = 0;
for (AssociationDescriptor anADesc : aDesc) {
if (found > 0)
b.append(", ");
found++;
b.append(anADesc.getName());
}
String failureReason = b.toString();
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return (false);
}
if(!AssociationMatcher.meetsOpposedRequirements(sElem, this)) {
String failureReason = AssociationMatcher.getLastErrorMessage();
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return (false);
}
if(!resourceCapability.measuredResourcesWithinRange()) {
StringBuilder buffer = new StringBuilder();
MeasuredResource[] m = resourceCapability.getMeasuredResources(ResourceCapability.MEASURED_RESOURCES_BREACHED);
for (MeasuredResource aM : m) {
buffer.append("\n");
buffer.append("[").append(aM.getIdentifier()).append("] ");
buffer.append("Low: ").append(aM.getThresholdValues().getLowThreshold()).append(", ");
buffer.append("High: ").append(aM.getThresholdValues().getHighThreshold()).append(", ");
buffer.append("Actual: ").append(aM.getValue());
}
String failureReason =
String.format("%s not selected to allocate service [%s], MeasuredResources have exceeded threshold constraints: %s",
getName(), LoggingUtil.getLoggingName(sElem), buffer.toString());
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return(false);
}
if(meetsGeneralRequirements(provisionRequest) && meetsQuantitativeRequirements(provisionRequest)) {
Collection<SystemComponent> unsupportedReqs = meetsQualitativeRequirements(provisionRequest);
if(unsupportedReqs.isEmpty()) {
logger.debug("{} meets qualitative requirements for [{}]", getName(), LoggingUtil.getLoggingName(sElem));
return (true);
} else {
/* Create a String representation of the unsupportedReqs
* object for logging */
int x = 0;
StringBuilder buffer = new StringBuilder();
for (SystemComponent unsupportedReq : unsupportedReqs) {
if (x > 0)
buffer.append(", ");
buffer.append("[").append(unsupportedReq.toString()).append("]");
x++;
}
String unsupportedReqsString = buffer.toString();
logger.debug("{} does not meet requirements for {} service [{}]",
getName(), provType, LoggingUtil.getLoggingName(sElem));
/* Determine if the resource supports persistent provisioning */
if(!resourceCapability.supportsPersistentProvisioning()) {
String failureReason =
String.format("Cannot allocate %s service [%s] to %s, required SystemComponents cannot be " +
"provisioned. This is because the %s is not configured for persistentProvisioning. " +
"If you want to enable this feature, verify the %s's configuration for the " +
"org.rioproject.cybernode.persistentProvisioning property is set to true",
provType, LoggingUtil.getLoggingName(sElem), getName(), getName(), getName());
provisionRequest.addFailureReason(failureReason);
logger.debug(failureReason);
return (false);
}
/*
* Check if the unsupported PlatformCapability objects can be
* provisioned. If there are any that cannot be provisioned move
* onto the next resource
*/
boolean provisionableCaps = true;
for (SystemComponent sysReq : unsupportedReqs) {
if (sysReq.getStagedSoftware()==null) {
provisionableCaps = false;
break;
}
}
if(!provisionableCaps) {
StringBuilder message = new StringBuilder();
message.append(getName()).append(" does not meet requirements for ");
message.append(provType).append(" service ");
message.append("[").append(LoggingUtil.getLoggingName(sElem)).append("] ");
message.append("PlatformCapability objects are not configured to be downloadable: ");
message.append(unsupportedReqsString);
String failureReason = message.toString();
provisionRequest.addFailureReason(failureReason);
logger.warn(failureReason);
return (false);
}
/* Get the size of the download(s) */
int requiredSize = 0;
IOException failed = null;
try {
for (SystemComponent sysReq : unsupportedReqs) {
StagedSoftware download = sysReq.getStagedSoftware();
if(download!=null) {
int size = download.getDownloadSize();
if(size < 0) {
logger.warn("Unable to obtain download size for {}, abort provision request",
download.getLocation());
requiredSize = size;
break;
}
requiredSize += size;
if(download.getPostInstallAttributes() != null &&
download.getPostInstallAttributes().getStagedData() != null) {
StagedData postInstall = download.getPostInstallAttributes().getStagedData();
size = postInstall.getDownloadSize();
if(size < 0) {
logger.warn("Unable to obtain download size for PostInstall {}, abort provision request",
postInstall.getLocation());
requiredSize = size;
break;
}
requiredSize += size;
}
}
}
} catch(IOException e) {
failed = e;
}
if (requiredSize < 0 || failed!=null)
throw new ProvisionException("Service ["+LoggingUtil.getLoggingName(sElem)+"] "+
"instantiation failed",
failed==null?
new IOException("Unable to obtain download size"):failed,
true);
/* Find out if the resource has the necessary disk-space */
if(supportsStorageRequirement(requiredSize, resourceCapability.getPlatformCapabilities())) {
logger.debug("{} supports provisioning requirements for {} service [{}]",
getName(), provType, LoggingUtil.getLoggingName(sElem));
sElem.setProvisionablePlatformCapabilities(unsupportedReqs);
return (true);
}
double avail = getAvailableStorage(resourceCapability.getPlatformCapabilities());
StringBuilder sb = new StringBuilder();
sb.append(getName()).append(" ");