Integrating OTRS with JIRA, Part I

Dont create your support topics here! No new topics with questions allowed!

Moderator: crythias

Forum rules
Dont create your support topics here! No new topics with questions allowed!
Post Reply
seberget2
Znuny newbie
Posts: 74
Joined: 17 May 2013, 09:30
Znuny Version: 6.0.30
Real Name: Stein Erik Berget

Integrating OTRS with JIRA, Part I

Post by seberget2 »

Hi there OTRS Community!
We use OTRS for our Service Desk, and R & D use JIRA for Change Management. Naturally we would like to integrate those two systems in a good way. Typically we would like to have a field or two in OTRS. So here is how we have integrated the two systems:
  1. jiraid to hold the jira identifier of type hubba-123
    1. Name: jiraid
    2. Label: Jira
    3. Field Order: (What you like it to be)
    4. Field Type: Text
    5. ObjectType: Ticket
    6. Default value: (blank)
    7. Show Link:

      Code: Select all

      https://<YOUR-JIRA-HOST>/browse/$LQData{"jiraid"}
      This makes a link that you can click on in OTRS and go directly to the JIRA ticket
  2. jirastate to hold the jira state
    1. Name: jirastate
    2. Label: Jira state
    3. Field Order: (What you like it to be)
    4. Field Type: Text
    5. ObjectType: Ticket
    6. Default value: (blank)
    7. Show Link: (blank)
Next we would like to show them somewhere. That can be configured using SysConfig in the OTRS admin interface. We would like to add these two fields on two different places (at least). One is to be able to edit the jiraid, and for showing them both. The jirastate we would like to be automatically updated.

So go into SysConfig and find the following config

Code: Select all

Frontend::Agent::Ticket::ViewFreeText
. In that page find the

Code: Select all

Ticket::Frontend::AgentTicketFreeText###DynamicField
block. Here you add jiraid as key, and 1 as content. This will make it possible to edit/set the value of the jiraid in the Free Text window on a ticket.

Next is to show the values of the two fields in the Ticket Information if they have content. That is done by doing the same as above but on the follwing SysConfig category:

Code: Select all

Ticket::Frontend::AgentTicketZoom###DynamicField
. Here you add two entries, one for jiraid and one for jirastate. The name of the field as key, and 1 as the content. The sort order are set by the Field order you set in the configuration of the Dynamic Fields.

If you now add a valid JIRA ID to a ticket in the Free Fields, and hit save you will now see a clickable link to Jira in the Ticket Information window. Next we need to get the state out of JIRA for those tickets.

Here I got inspiration from https://github.com/rttag/RTT-JiraWebhook. Basically we are going to use the Web Hook call back feature of JIRA https://developer.atlassian.com/display ... s+Overview. To use that we need to set up a thing on the OTRS server to handle the POST request from JIRA.

The following is the content of the file

Code: Select all

<OTRS-INSTALL-DIR>/bin/cgi-bin/jira.pl

Code: Select all

#!/usr/bin/perl
#
# RTT-JiraWebhook
#
# Copyright (C) 2013-2014 Realtime Technology AG, http://rtt.ag/
#
# Author: Martin Gross <martin.gross@rtt.ag>
# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, November 2007
#
# THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
# KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
# PARTICULAR PURPOSE.
#
# Amended by: Stein Erik Berget, seberget@esenic.com
#

use strict;
use warnings;

use FindBin qw($Bin);
use lib "$Bin/../..";
use lib "$Bin/../../Kernel/cpan	-lib";
use lib "$Bin/../../Custom";

use Kernel::System::Encode;
use Kernel::System::Log;
use Kernel::System::Time;
use Kernel::System::DB;
use Kernel::System::Main;
use Kernel::Config;
use Kernel::System::Ticket;

use CGI;
use JSON::XS;

# create common objects
my %CommonObject = ();
$CommonObject{ConfigObject} = Kernel::Config->new();
$CommonObject{LogObject}    = Kernel::System::Log->new(
  LogPrefix => 'JIRA Webhook',
  %CommonObject,
);
$CommonObject{MainObject}   = Kernel::System::Main->new(%CommonObject);
$CommonObject{TimeObject}   = Kernel::System::Time->new(%CommonObject);
$CommonObject{DBObject}     = Kernel::System::DB->new(%CommonObject);
$CommonObject{TicketObject} = Kernel::System::Ticket->new(%CommonObject);

my $q = new CGI;
my @fields = $q->param();

print $q->header();

my $jsondata;

if (!defined($q->param('POSTDATA'))) {
  exit('No Postdata!');
}

$jsondata = decode_json($q->param('POSTDATA'));

my @TicketIDs = $CommonObject{TicketObject}->TicketSearch(
  Result => 'ARRAY',
  DynamicField_jiraid => {
    Equals  => $jsondata->{'issue'}->{'key'},
  },
  UserID      => '1',
  Permission  => 'rw',
  CacheTTL    => '1',
);

foreach my $TicketID(@TicketIDs) {
  my %Ticket = $CommonObject{TicketObject}->TicketGet(
    TicketID  => $TicketID,
    UserID    => 1,
  );


  my $newState = $jsondata->{'issue'}->{'fields'}->{'status'}->{'name'};
  my $oldState = $CommonObject{TicketObject}->{DynamicFieldBackendObject}->ValueGet(
    DynamicFieldConfig => $CommonObject{TicketObject}->{DynamicFieldObject}->DynamicFieldGet(Name => "jirastate"),
    ObjectID           => $TicketID,  
  );
  
  if ($newState ne $oldState) {
    $CommonObject{TicketObject}->{DynamicFieldBackendObject}->ValueSet(
      DynamicFieldConfig => $CommonObject{TicketObject}->{DynamicFieldObject}->DynamicFieldGet(Name => "jirastate"),
      ObjectID           => $TicketID,
      Value              => $newState,
      UserID             => 1,
    );
  }
}
This is the target for the web hook we configure in JIRA. Basically it takes in JSON data from JIRA, searches for tickets with the given JIRA ID, and sets the jirastate field if the new value is different than the stored one. See https://developer.atlassian.com/display ... s+Overview for how to configure a hook. I've registed my hook to only be invoked on Issue updated.

This next part is optional.
I wanted to do as litle custom development as possible, and make use of the standard features of OTRS. Since I'm on OTRS 3.3.3 I can use the Event feature of GenericAgent. There I've configured to listen to

Code: Select all

Ticket:TicketDynamicFieldUpdate_jirastate
events. When this happens I add a note to the ticket in question saying that please check if this state change are something we should inform the customer about. By doing it here, we can change our mind, do other filtering and what not directly in the GUI of OTRS, and not dig around in code to do it.

The first time you create the link from OTRS the jirastate field will be empty. Which is something I hope I'll fix in part II of this endeavour. That is have OTRS invoke JIRA with a webhook like feature so I'll add the OTRS ticket ID to a field in JIRA. To be continued...
OTRS 6.0.12 on Ubuntu with MySQL DB, and various plug-ins and a hack or two :-D
jojo
Znuny guru
Posts: 15019
Joined: 26 Jan 2007, 14:50
Znuny Version: Git Master
Contact:

Re: Integrating OTRS with JIRA, Part I

Post by jojo »

Thanks, If you won't mind I'll move it to the How To section
"Production": OTRS™ 8, OTRS™ 7, STORM powered by OTRS
"Testing": ((OTRS Community Edition)) and git Master

Never change Defaults.pm! :: Blog
Professional Services:: http://www.otrs.com :: enjoy@otrs.com
seberget2
Znuny newbie
Posts: 74
Joined: 17 May 2013, 09:30
Znuny Version: 6.0.30
Real Name: Stein Erik Berget

Re: Integrating OTRS with JIRA, Part I

Post by seberget2 »

jojo wrote:Thanks, If you won't mind I'll move it to the How To section
Please feel free to do that.
OTRS 6.0.12 on Ubuntu with MySQL DB, and various plug-ins and a hack or two :-D
seberget2
Znuny newbie
Posts: 74
Joined: 17 May 2013, 09:30
Znuny Version: 6.0.30
Real Name: Stein Erik Berget

Re: Integrating OTRS with JIRA, Part I

Post by seberget2 »

I've found that I had to make one change to the code from

Code: Select all

$jsondata = decode_json($q->param('POSTDATA'));
to

Code: Select all

my $json_utf8 = encode('UTF-8', $q->param('POSTDATA'));
$jsondata = JSON->new->utf8->decode($json_utf8);
Mainly because we had text in JIRA that was not valid UTF-8. This is fixed by the above code.
OTRS 6.0.12 on Ubuntu with MySQL DB, and various plug-ins and a hack or two :-D
lanoxx
Znuny newbie
Posts: 1
Joined: 17 Sep 2014, 10:00
Znuny Version: 3.3.9
Real Name: Sebastian

Re: Integrating OTRS with JIRA, Part I

Post by lanoxx »

Hi,

I have tried your script but I am getting an error:
[Wed Sep 17 09:48:49 2014] [error] [Wed Sep 17 09:48:49 2014] -e: Got no EncodeObject! at /opt/otrs//Kernel/System/DB.pm line 94.\n
It is caused by this line in the code:

Code: Select all

$CommonObject{DBObject}     = Kernel::System::DB->new(%CommonObject);
Do you have any idea/suggestion what this error is appearing or how to fix it. Unfortunately I am not a Perl developer but usually develop in Java, so I had not much success when I tried to find the cause of this issue.

I am getting this error when I execute the following url in the browser:

Code: Select all

http://myserver.x.y/otrs/jira.pl
and it returns an error 500. Unfortunately I do not know the format of the JSON that Jira sends or I could test it with a JSON plugin such as Postman.
seberget2
Znuny newbie
Posts: 74
Joined: 17 May 2013, 09:30
Znuny Version: 6.0.30
Real Name: Stein Erik Berget

Re: Integrating OTRS with JIRA, Part I

Post by seberget2 »

lanoxx wrote:Do you have any idea/suggestion what this error is appearing or how to fix it. Unfortunately I am not a Perl developer but usually develop in Java, so I had not much success when I tried to find the cause of this issue.
I'm actually a java developer my self. Please add the

Code: Select all

$CommonObject{EncodeObject} = Kernel::System::Encode->new(%CommonObject);
line somewhere above the line that fails, and all should be well. I'm sorry that I've not responded to this sooner.

I will publish this as a proper OTRS module so the installation and upgradeability of OTRS will be improved. I will publish it so it' available at http://opar.perl-services.de/

Have a happy day!
OTRS 6.0.12 on Ubuntu with MySQL DB, and various plug-ins and a hack or two :-D
Amukinado
Znuny newbie
Posts: 76
Joined: 02 Jun 2010, 15:52
Znuny Version: 3.2.8
Location: Portugal

Re: Integrating OTRS with JIRA, Part I

Post by Amukinado »

Hello. I would like to use this with OTRS 4.0.8. I've been trying to change Object Management declarations, because it seems to me that's the problem, but not even a developer, so it's not that clear for me.

this is my apache log error, can you please help?

Code: Select all

[Before messing around with object declarations (http://otrs.github.io/doc/manual/developer/4.0/en/html/package-porting.html) ]
[Mon Jul 13 16:52:41.543678 2015] [:error] [pid 14004] $Kernel::OM is not defined, please initialize your object manager at /opt/otrs//Kernel/System/Log.pm line 61.\n\tKernel::System::Log::new('Kernel::System::Log', 'LogPrefix', 'JIRA Webhook', 'ConfigObject', 'Kernel::Config=HASH(0x7fae2864c5b0)') called at /opt/otrs/bin/cgi-bin/jira.pl line 40\n\tModPerl::ROOT::ModPerl::Registry::opt_otrs_bin_cgi_2dbin_jira_2epl::handler('Apache2::RequestRec=SCALAR(0x7fae26a7c9b8)') called at /usr/lib64/perl5/vendor_perl/ModPerl/RegistryCooker.pm line 207\n\teval {...} called at /usr/lib64/perl5/vendor_perl/ModPerl/RegistryCooker.pm line 207\n\tModPerl::RegistryCooker::run('ModPerl::Registry=HASH(0x7fae25a72c78)') called at /usr/lib64/perl5/vendor_perl/ModPerl/RegistryCooker.pm line 173\n\tModPerl::RegistryCooker::default_handler('ModPerl::Registry=HASH(0x7fae25a72c78)') called at /usr/lib64/perl5/vendor_perl/ModPerl/Registry.pm line 32\n\tModPerl::Registry::handler('ModPerl::Registry', 'Apache2::RequestRec=SCALAR(0x7fae26a7c9b8)') called at -e line 0\n\teval {...} called at -e line 0\n



[After making some changes]




[Mon Jul 13 17:13:12.635309 2015] [:error] [pid 15366] Global symbol "%CommonObject"                                                                                                                           requires explicit package name at /opt/otrs/bin/cgi-bin/jira.pl line 73.\nGlobal symb                                                                                                                          ol "%CommonObject" requires explicit package name at /opt/otrs/bin/cgi-bin/jira.pl li                                                                                                                          ne 84.\nGlobal symbol "%CommonObject" requires explicit package name at /opt/otrs/bin                                                                                                                          /cgi-bin/jira.pl line 91.\nGlobal symbol "%CommonObject" requires explicit package na                                                                                                                          me at /opt/otrs/bin/cgi-bin/jira.pl line 92.\nGlobal symbol "%CommonObject" requires                                                                                                                           explicit package name at /opt/otrs/bin/cgi-bin/jira.pl line 97.\nGlobal symbol "%Comm                                                                                                                          onObject" requires explicit package name at /opt/otrs/bin/cgi-bin/jira.pl line 98.\n

Code: Select all

[Changes made by my are below original commented code]
use JSON::XS;

# create common objects


local $Kernel::OM = Kernel::System::ObjectManager->new(
    'Kernel::System::Log' => {
        LogPrefix => 'JIRA Webhook',
    },
);
#my %CommonObject = ();
#$CommonObject{ConfigObject} = Kernel::Config->new();
#$CommonObject{LogObject}    = Kernel::System::Log->new(
#  LogPrefix => 'JIRA Webhook',
#  %CommonObject,
#);
#$CommonObject{MainObject}   = Kernel::System::Main->new(%CommonObject);
#$CommonObject{TimeObject}   = Kernel::System::Time->new(%CommonObject);
#$Object{EncodeObject} = Kernel::System::Encode->new(%CommonObject);
#$CommonObject{DBObject}     = Kernel::System::DB->new(%CommonObject);
#$CommonObject{TicketObject} = Kernel::System::Ticket->new(%CommonObject);

my $q = new CGI;
my @fields = $q->param();

print $q->header();

my $jsondata;

if (!defined($q->param('POSTDATA'))) {
  exit('No Postdata!');
}


BTW, have you already released the plugin on your page? Under wich name?

Thanks in advance.
Regards.
OTRS V3.2.8 - ITSM 3.2.6 - Cent OS 5.9x64
seberget2
Znuny newbie
Posts: 74
Joined: 17 May 2013, 09:30
Znuny Version: 6.0.30
Real Name: Stein Erik Berget

Re: Integrating OTRS with JIRA, Part I

Post by seberget2 »

Amukinado wrote:Hello. I would like to use this with OTRS 4.0.8. I've been trying to change Object Management declarations, because it seems to me that's the problem, but not even a developer, so it's not that clear for me.
I'm sorry but I've got no access to a OTRS 4 installation, so I don't know what to change, sorry.
Amukinado wrote:BTW, have you already released the plugin on your page? Under wich name?
No I've not released this as of now. I'll post updates here when I do.
OTRS 6.0.12 on Ubuntu with MySQL DB, and various plug-ins and a hack or two :-D
ruzzetto

Re: Integrating OTRS with JIRA, Part I

Post by ruzzetto »

if could be help, in OTRS 5 the link in this way

Code: Select all

https://<YOUR-JIRA-HOST>/browse/$LQData{"jiraid"}
does not work for me.
I change in this way:

Code: Select all

https://MYJIRA/browse/[% Data."mydynamicafield (in my case JIRAID)" | uri %]
Bye
Post Reply