We are on IIQ 8.3
I am using a Run Rule Task to run the follow rule I found on Compass. I’m trying to delete all Filtered Provisioning Transactions, currently around 60 million of our 90 million transactions seem to meet this criteria.
24 hours into the run and it has deleted 1 million, meaning it could take 2 months to complete the task!?!
Anyone know of a more efficient way to get this done, or just let it run and hope for the best?
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule created="1731430519689" id="0aab09ca92e313d98193214d13897b5c" language="beanshell" modified="1732324253269" name="PurgeFilteredProvisioningTransactions">
<Description>
This rule cleans up Filtered provisioning transactions of access that already exists.
</Description>
<Source>
import java.util.Calendar;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import sailpoint.api.IdIterator;
import sailpoint.api.SailPointContext;
import sailpoint.api.SailPointFactory;
import sailpoint.api.Terminator;
import sailpoint.object.Attributes;
import sailpoint.object.ProvisioningPlan.AccountRequest;
import sailpoint.object.ProvisioningPlan.AttributeRequest;
import sailpoint.object.Capability;
import sailpoint.object.Field;
import sailpoint.object.Filter;
import sailpoint.object.Form;
import sailpoint.object.Identity;
import sailpoint.object.ProvisioningProject;
import sailpoint.object.ProvisioningTransaction;
import sailpoint.object.QueryOptions;
import sailpoint.object.TaskResult;
import sailpoint.tools.GeneralException;
import sailpoint.tools.Util;
int count = 0;
int delCount = 0;
// ====================== IMPORTANT ==========================
// For testing without deleting objects: set readOnly = true
// Once fully tested, set readOnly = false
// ====================== IMPORTANT ==========================
boolean readOnly = false;
Terminator terminatorObj = new Terminator(context);
QueryOptions qo = new QueryOptions();
qo.addFilter(Filter.eq("status", "Success"));
qo.addFilter(Filter.eq("integration", "Filtered"));
// If we don't want a specific time range, then set this flag to false.
boolean useTimeFilter = false;
TaskResult taskResult = null;
if (useTimeFilter) {
Calendar beforeCal = Calendar.getInstance();
beforeCal.set(Calendar.HOUR_OF_DAY, 0);
beforeCal.set(Calendar.MINUTE, 0);
beforeCal.set(Calendar.SECOND, 0);
beforeCal.set(Calendar.MILLISECOND, 0);
Calendar afterCal = Calendar.getInstance();
// Default behavior: only scan provisioning transactions created in the past 30 days
afterCal.add(Calendar.DAY_OF_MONTH, -30);
qo.addFilter(Filter.and(Filter.gt("created", afterCal.getTime()), Filter.le("created", beforeCal.getTime())));
}
Iterator it = context.search(ProvisioningTransaction.class, qo, "id");
IdIterator idIt = new IdIterator(context, it);
try {
while (idIt.hasNext()) {
if (taskResult != null && taskResult.isTerminateRequested()) {
return ("Terminated");
}
count++;
String id = (String) idIt.next();
ProvisioningTransaction pt = (ProvisioningTransaction) context.getObjectById(ProvisioningTransaction.class, id);
if (pt != null) {
Object filtered = pt.getAttributes().get(ProvisioningTransaction.ATT_FILTERED);
boolean purgeTransaction = true;
if (filtered instanceof AccountRequest) {
List attList = ((AccountRequest) filtered).getAttributeRequests();
for (AttributeRequest att : attList) {
Object reasonVal = att.get(ProvisioningProject.ATT_FILTER_REASON);
if (reasonVal != null) {
if (reasonVal.equals(ProvisioningProject.FilterReason.Exists)) {
log.debug("ProvisioningTransaction found: " + id + ", reason: " + reasonVal);
} else {
// If ProvTrans contains projects with a reason other than "exists", then don't purge it.
// I'm not sure this is exactly what we want, so more testing needs to be done here.
purgeTransaction = false;
}
// boolean flag is AND-ed for each attribute request; once the flag becomes false, it will remain false.
purgeTransaction &= purgeTransaction;
}
}
} else {
purgeTransaction = false;
}
if (purgeTransaction) {
if (!readOnly) {
terminatorObj.deleteObject(pt);
}
delCount++;
}
}
if (count % 100 == 0) {
if (!readOnly)
context.commitTransaction();
context.decache();
System.out.println("Current deleted count is - " + delCount);
}
}
} catch (Exception ex) {
log.error("ProvisioningTransaction.Cleanup: ", ex);
} finally {
if (!readOnly)
context.commitTransaction();
context.decache();
sailpoint.tools.Util.flushIterator(it);
}
if (taskResult != null) {
Attributes resultAttributes = new Attributes();
resultAttributes.put("provtrans_total", count);
resultAttributes.put("provtrans_purged", delCount);
taskResult.setAttributes(resultAttributes);
}
return "Total scanned: " + count + ", purged: " + delCount;
</Source>
</Rule>
Thank you!