Linking Incident report to respective Incident based on some custom field values


#1

Hello Community,

Please help us achieve the below logic.In simple words, How to link Incident report to respective Incident based on some custom field values?

Logic:

  1. Fetch all the open Incidents
  2. Iterate through open Incidents
    If (concatenation(Source IP and Destination IP values) == ‘Incident Condition’ value)
    {
    Link (Incident Report --> Respective Incident);
    }

Note:

  • Custom fields, ‘Source IP’ and ‘Destination IP’ are part of ‘IDS Alerts’ (Incident report) queue.
  • Custom field, ‘Incident Condition’ is part of ‘Incidents’ queue.

Started writing below Scrip to achieve the above, but stuck…

Condition:
On Create

Custom action:

my $queue = ‘IDS Alerts’;
my $cf_value_sip = $self->TicketObj->CustomFieldValuesAsString(‘Source IP’);
my $cf_value_dip = $self->TicketObj->CustomFieldValuesAsString(‘Destination IP’);

RT::LoadConfig();
RT::Init();
my $tx = RT::Tickets->new($RT::SystemUser);
my $cf = RT::CustomField->new($RT::SystemUser);
my $q = RT::Queue->new($RT::SystemUser);
$q->Load($queue);
$cf->LoadByNameAndQueue(Queue => $q->Id, Name => $cf_name);

my $concat_sip_dip = $cf_value_sip.$cf_value_dip;
if ($concat_sip_dip eq ‘Incident Condition’ value);
{
Link (Incident Report --> Incident);
}


#2

I wrote below Custom Action. Can anybody please make this work?

my $queue = ‘Incidents’;
my $type = ‘MemberOf’;
my $cf_name = ‘Incident Condition’;
my $cf_value_sip = $self->TicketObj->CustomFieldValuesAsString(‘Source IP’);
my $cf_value_dip = $self->TicketObj->CustomFieldValuesAsString(‘Destination IP’);

RT::LoadConfig();
RT::Init();
my $tx = RT::Tickets->new($RT::SystemUser);
my $cf = RT::CustomField->new($RT::SystemUser);
my $q = RT::Queue->new($RT::SystemUser);
$q->Load($queue);
$cf->LoadByNameAndQueue(Queue => $q->Id, Name => $cf_name);

my $concat_sip_dip = $cf_value_sip.$cf_value_dip;

$tx->FromSQL(qq[queue="$queue" AND Status = ‘open’]);

while (my $t = $tx->Next)
{
my $cf_incident_condition_value = $t->CustomFieldValuesAsString($cf_name);
if ($concat_sip_dip eq $cf_incident_condition_value);
{
link_tickets (src => $cf->id, dst => $t->id, link_type => $type)
}
}


#3

This while loop method would be a slower way to do it especially if you ever have a lot of tickets with open status. I would add the field value to the search and then link everything that resulted from the search.

What I do is I build and execute the search like the following. We want to link the Incident Report to all the relative Incidents based on the Class, SubClass, Device Name and Customer ID values. If it’s the same class, subclass, device name and customer ID then it’s the same Incident. The ticket can be open or resolved but has to be resolved within the last month.

my $sql = "Queue = 'Incidents' 
            AND 'CF.{Class}' = '" . $self->TicketObj->FirstCustomFieldValue('Class') . "' 
            AND 'CF.{SubClass}' = '" . $self->TicketObj->FirstCustomFieldValue('SubClass') . "' 
            AND 'CF.{Device Name}' = '" . $self->TicketObj->FirstCustomFieldValue('Device Name') . "'
            AND 'CF.{Customer ID}' = '" . $self->TicketObj->FirstCustomFieldValue('Customer ID') . "'
            AND ( Status = 'open' OR (Status = 'resolved' AND Resolved > '1 month ago') )";

$incidents->FromSQL($sql);

# Stop if there are none to link to
return 0 if $incidents->Count == 0;

Then link each of the results to the current ticket (and change the owner to match etc):

while( my $incident = $incidents->Next ) {
    $self->TicketObj->AddLink( Type => 'MemberOf', Target => $incident->id );
    $self->TicketObj->SetOwner($incident->Owner);
}

I wrote this into a module instead of using a scrip so for you $self->TicketObj would probably be $Ticket.

If you still have trouble after this please share the entire code again (not pseudo code) and make sure to format it as code (</> in the menu above the edit box) and I’ll have another look at it.


#4

Hello Landon,

Thanks for offering the help here. For the sake of simplicity, I modified the scrip like below, but still no success. This scrip is part of ‘IDS Alerts’ queue. It triggers when condition is ‘On Create’.

Custom action preparation code:

my $type = 'MemberOf';
my $txn = $self->TransactionObj;
my $tx = RT::Tickets->new($RT::SystemUser);
my $sql = "Queue = 'Incidents' 
            AND 'CF.{Source IP}' = '" . $self->TicketObj->CustomFieldValuesAsString('Source IP') . "' 
            AND 'CF.{Source HostName}' = '" . $self->TicketObj->CustomFieldValuesAsString('Source HostName') . "' 
            AND ( Status = 'open')";

$incidents->FromSQL($sql);

# Stop if there are none to link to
return 0 if $incidents->Count == 0;

while( my $incident = $incidents->Next ) 
{	
  $self->TicketObj->SetStatus('open');
  $self->TicketObj->SetOwner($incident->Owner);
  #$self->TicketObj->AddLink( Type => 'MemberOf', Target => $incident->id );
  #link_tickets (src => $txn->id, dst => $incident->id, link_type => $type);
  #link_tickets (src => $tx->id, dst => $incident->id, link_type => $type);
  $self->TicketObj->MergeInto($incident->id);
}

Note:

  • For some reason, ‘FirstCustomFieldValue’ is not working. Hence, I replaced it with ‘CustomFieldValuesAsString’ in scrip.

  • I am using RT v4.4. It seems we need to consider merge option. May be I am wrong.

  • I tried all linking methods. Still no luck.

To make things clear, I am looking to link the Incident Report to all the relative Incidents based on the Source IP and Source HostName. In other words, Incident report matching this criterion should appear in Incident Reports section of Incident with status as open.


#5

Why not pop a “warn” or RT::Logger entry in after creating the $sql variable so that you can check what it contains? That may give a hint as to what is wrong. If the SQL looks sensible you can always check the individual parts in the database itself too.


#6

@GreenJimll Thank you! will check this way…


#7

Finally, I am able to achieve the objective with the below code. Thanks @Landon and @GreenJimll for helping me in this case.

#!/home/perl/bin/perl
use strict;
use warnings;
use lib qw(/opt/rt4/lib); # This depends on your installation paths. In this case RT resides in /opt
use RT;
use RT::Queues;
use RT::Tickets;
use Data::Dumper;
use RT::Link;

# CONFIGURATION
my $queue = 'Incidents';               # You can change this value. This depends on where(Queue) the custom field resides
my $cf_name = 'Incident Condition';    # You can change this value. This depends on the custom field you created through GUI
my $type = 'MemberOf';
# END CONFIGURATION

RT::LoadConfig();
RT::Init();
my $tx = RT::Tickets->new($RT::SystemUser);
my $cf = RT::CustomField->new($RT::SystemUser);
my $q  = RT::Queue->new($RT::SystemUser);
my $sip = $self->TicketObj->CustomFieldValuesAsString('Source IP');
my $shost= $self->TicketObj->CustomFieldValuesAsString('Source HostName');
my $concat = $sip.$shost;

$tx->FromSQL(qq[queue="$queue" and Status="open" and "cf.$queue.{$cf_name}" = '$concat']);
$q->Load($queue);
$cf->LoadByNameAndQueue(Queue => $q->Id, Name => $cf_name);
unless( $cf->id ) 
{
    # queue 0 is special case and is a synonym for global queue
    $cf->LoadByNameAndQueue( Name => $cf_name, Queue => '0' );
}
unless( $cf->id ) 
{
    print "No field $cf_name in queue ". $q->Name;
    die "Could not load custom field";
}

my $i=0;
while (my $t = $tx->Next) 
{
    print "Processing/ Linking record #" . ++$i . "\n";
    my $cf_value = $t->CustomFieldValuesAsString($cf_name);
    if ($concat eq $cf_value)
    {   
        print "Incident found!" ;
        $self->TicketObj->SetStatus($t->Status);
        $self->TicketObj->SetOwner($t->Owner);
        my ($status, $msg) = $self->TicketObj->AddLink( Type => 'MemberOf', Target => $t->Id );
        #link_tickets (src => $self->TicketObj->Id, dst => $t->Id, link_type => $type);
        $RT::Logger->error("Couldn't link: $msg");
        print "Link completed!" . ++$i . "\n";
    }
    
}