IIQ allows you to run any Rule as a Task via the TaskDefintion called “Run Rule”. This is fine for most use cases, but in our customization, we have found that we want to run a Rule on all of our Identities or ManagedAttributes. In these cases, a single partitioned solution is not practical even if it is multithreaded by convention means. To this end, I have developed a new TaskDefinition type “Partitioned Rule”. This TaskDefinition takes a rule, SailPointObject class name, and a few other parameters to partition your objects and get reasonable running time for rules that need to run on all of your objects.
The specific motivation for making this TaskDefinition, and its infrastructure, was to fulfill a business requirement to trigger PolicyViolations on ManagedAttributes (AD Groups). As PolicyViolations are set up today, they only run on Identities. In my tinkering found how I could use the existing advance Policy template to take a ManagedAttribute and create the PolicyViolation but we lost the inbuilt partitioning granted to us by using an Identity refresh. This was simply unacceptable; It would take over 12 hours to chug through all of the objects. If we used the Rule, even if it were multi threaded, it would have taken over 8 hrs. The solution was to create this “Partitioned Rule” TaskDefinition. On implementation, all the objects are assigned to a partition and executed individually, similar to how Identity refresh works.
We use the SSB (Services Standard Build) for our build and having an understanding of how to customize IIQ using the SSB will be helpful. The main reason is that I use several Java files to implement this infrastructure of “Partitioned Rule”. If anyone out there wants to make, a purely BeanShell version feel free to reply to this thread or message me so we can get the code out there.
Essentially you simply need to download the code, put it into your source, build, deploy, and import. Double check your package locations match between your Java files and BeanShell. Once imported you should be able to go to the Task window, click the “New Task” in the upper right, scroll down to “Partitioned Rule” and start filling out the fields.
“objectClassName” is the name of the SailPointObject that you want to iterate over. This is slightly technical, but in the Identity refresh case, you are iteration over “Identity”. In my example above I am iteration over “ManagedAttribute”. Technically you can iterate over any SailPointObject like TaskResult, Policy, Audit, and much more.
“rule” is the Rule that you want to run on each object. The thing to note here is that you are running this rule on every object one at a time, as such, your Rule should expect a single object to act on. You do not want your Rule to expect to be running on a list of objects.
“rConfig” is the config that is passed to the Rule that you supplied above. You don’t need to supply the SailPointObject or TaskDefinition, “Partitioned Rule” does this for you. But if your Rule has other configurations you wish to supply this is where you would do it. We use this field for maxRetries and timeout values. If you have no config for your Rule, you can leave this blank.
“debugMode” is a safety flag that I added for our use case. “Partitioned Rule” only passes this value along to your Rule. If you choose not to implement “debugMode” in your Rule, then you can leave this field blank. If you do implement it, you should supply the string “true” or “false”. 6.4p4 had a weird quirk with the boolean check make that did not behave as expected if you uncheck the box. I have not tried in 7.1 yet.
“partitionSize” is the size that you want each partition to be. I have a limiter in the code that if you go over 100 partitions, it instantly fails. This is to avoid accidentally supplying a small number and getting a huge number of partitions bring your task to a crawl.
If you have any questions feel free to reply to this thread, I’ll do my best to get back to you. And, if you are interested in how I finished solving the Policy problem above let me know, and I’ll work on a new article for an article addressing it.
OOTBParition.jar -
I'm almost positive that this will not work like that. When I compile using SSB the class files endup in WEB-INF/classes. You might be able to put them in there manually; But, that's not a substanable way to deploy your code.
Hi Jotorres,
Really appreciate the custom partitioned rule task.
Please help me with the code only in beanshell without having java classes.
How to convert PartitionedRuleContainer.java and RuleRequestExecutor.java code in beanshell.
Thanks,
Sowmya
If anyone out there wants to make, a purely BeanShell version feel free to reply to this thread or message me so we can get the code out there.
@jotorres , Appreciate what you've done here! Just curious, has anyone reached out to you with a purely BeanShell version or have you come up with one by any chance?
Hey, Finally I got it working. But some of the Partition is running long time and not finishing at all. Tried couple of time but nothing is printed in the log. Any idea where to check for the issue?
An example - partition 1 got hung
Here is the Task Result -
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE TaskResult PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<TaskResult created="" host="****" id="" launched="1624567241810" launcher="****" modified="" name="Sync Task Partition Task" partitioned="true" runLengthAverage="311" schedule="" type="Generic">
<Attributes>
<Map>
<entry key="Result: " value="Success"/>
<entry key="taskResultPartitions">
<value>
<List>
<TaskResult name="partition 1">
<Attributes>
<Map>
<entry key="Success">
<value>
<Integer>3000</Integer>
</value>
</entry>
</Map>
</Attributes>
</TaskResult>
<TaskResult completed="1624567535875" completionStatus="Success" host="*********" launched="1624567313149" name="partition 2">
<Attributes>
<Map>
<entry key="Success">
<value>
<Integer>3000</Integer>
</value>
</entry>
</Map>
</Attributes>
</TaskResult>
<TaskResult completed="1624567526504" completionStatus="Success" host="********" launched="1624567346611" name="partition 3">
<Attributes>
<Map>
<entry key="Success">
<value>
<Integer>3000</Integer>
</value>
</entry>
</Map>
</Attributes>
</TaskResult>
<TaskResult completed="1624567806138" completionStatus="Success" host="*********" launched="1624567381220" name="partition 4">
<Attributes>
<Map>
<entry key="Success">
<value>
<Integer>3000</Integer>
</value>
</entry>
</Map>
</Attributes>
</TaskResult>
<TaskResult completed="1624568281950" completionStatus="Success" host="********" launched="1624567414407" name="partition 5">
<Attributes>
<Map>
<entry key="Success">
<value>
<Integer>1754</Integer>
</value>
</entry>
</Map>
</Attributes>
</TaskResult>
</List>
</value>
</entry>
<entry key="violationResults">
<value>
<PolicyImpactAnalysis policyName="placeHolder"/>
</value>
</entry>
</Map>
</Attributes>
<Definition>
<Reference class="sailpoint.object.TaskDefinition" id="8a62d3b37a0c2c36017a0c30e34c0006" name="Sync Task Partition Task"/>
</Definition>
<Owner>
<Reference class="sailpoint.object.Identity" id="****" name="****"/>
</Owner>
<Progress>Completed 4 of 5 partitions</Progress>
</TaskResult>