summaryrefslogtreecommitdiffstats
path: root/extensions/Push/lib/Connector.disabled
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/Push/lib/Connector.disabled')
-rw-r--r--extensions/Push/lib/Connector.disabled/AMQP.pm344
-rw-r--r--extensions/Push/lib/Connector.disabled/ServiceNow.pm690
2 files changed, 514 insertions, 520 deletions
diff --git a/extensions/Push/lib/Connector.disabled/AMQP.pm b/extensions/Push/lib/Connector.disabled/AMQP.pm
index 1ba365e21..dda73dade 100644
--- a/extensions/Push/lib/Connector.disabled/AMQP.pm
+++ b/extensions/Push/lib/Connector.disabled/AMQP.pm
@@ -20,211 +20,197 @@ use Bugzilla::Util qw(generate_random_password);
use DateTime;
sub init {
- my ($self) = @_;
- $self->{mq} = 0;
- $self->{channel} = 1;
-
- if ($self->config->{queue}) {
- $self->{queue_name} = $self->config->{queue};
- } else {
- my $queue_name = Bugzilla->localconfig->{'urlbase'};
- $queue_name =~ s#^https?://##;
- $queue_name =~ s#/$#|#;
- $queue_name .= generate_random_password(16);
- $self->{queue_name} = $queue_name;
- }
+ my ($self) = @_;
+ $self->{mq} = 0;
+ $self->{channel} = 1;
+
+ if ($self->config->{queue}) {
+ $self->{queue_name} = $self->config->{queue};
+ }
+ else {
+ my $queue_name = Bugzilla->localconfig->{'urlbase'};
+ $queue_name =~ s#^https?://##;
+ $queue_name =~ s#/$#|#;
+ $queue_name .= generate_random_password(16);
+ $self->{queue_name} = $queue_name;
+ }
}
sub options {
- return (
- {
- name => 'host',
- label => 'AMQP Hostname',
- type => 'string',
- default => 'localhost',
- required => 1,
- },
- {
- name => 'port',
- label => 'AMQP Port',
- type => 'string',
- default => '5672',
- required => 1,
- validate => sub {
- $_[0] =~ /\D/ && die "Invalid port (must be numeric)\n";
- },
- },
- {
- name => 'username',
- label => 'Username',
- type => 'string',
- default => 'guest',
- required => 1,
- },
- {
- name => 'password',
- label => 'Password',
- type => 'password',
- default => 'guest',
- required => 1,
- },
- {
- name => 'vhost',
- label => 'Virtual Host',
- type => 'string',
- default => '/',
- required => 1,
- },
- {
- name => 'exchange',
- label => 'Exchange',
- type => 'string',
- default => '',
- required => 1,
- },
- {
- name => 'queue',
- label => 'Queue',
- type => 'string',
- },
- );
+ return (
+ {
+ name => 'host',
+ label => 'AMQP Hostname',
+ type => 'string',
+ default => 'localhost',
+ required => 1,
+ },
+ {
+ name => 'port',
+ label => 'AMQP Port',
+ type => 'string',
+ default => '5672',
+ required => 1,
+ validate => sub {
+ $_[0] =~ /\D/ && die "Invalid port (must be numeric)\n";
+ },
+ },
+ {
+ name => 'username',
+ label => 'Username',
+ type => 'string',
+ default => 'guest',
+ required => 1,
+ },
+ {
+ name => 'password',
+ label => 'Password',
+ type => 'password',
+ default => 'guest',
+ required => 1,
+ },
+ {
+ name => 'vhost',
+ label => 'Virtual Host',
+ type => 'string',
+ default => '/',
+ required => 1,
+ },
+ {
+ name => 'exchange',
+ label => 'Exchange',
+ type => 'string',
+ default => '',
+ required => 1,
+ },
+ {name => 'queue', label => 'Queue', type => 'string',},
+ );
}
sub stop {
- my ($self) = @_;
- if ($self->{mq}) {
- Bugzilla->push_ext->logger->debug('AMQP: disconnecting');
- $self->{mq}->disconnect();
- $self->{mq} = 0;
- }
+ my ($self) = @_;
+ if ($self->{mq}) {
+ Bugzilla->push_ext->logger->debug('AMQP: disconnecting');
+ $self->{mq}->disconnect();
+ $self->{mq} = 0;
+ }
}
sub _connect {
- my ($self) = @_;
- my $logger = Bugzilla->push_ext->logger;
- my $config = $self->config;
-
- $self->stop();
-
- $logger->debug('AMQP: Connecting to RabbitMQ ' . $config->{host} . ':' . $config->{port});
- require Net::RabbitMQ;
- my $mq = Net::RabbitMQ->new();
- $mq->connect(
- $config->{host},
- {
- port => $config->{port},
- user => $config->{username},
- password => $config->{password},
- }
- );
- $self->{mq} = $mq;
-
- $logger->debug('AMQP: Opening channel ' . $self->{channel});
- $self->{mq}->channel_open($self->{channel});
-
- $logger->debug('AMQP: Declaring queue ' . $self->{queue_name});
- $self->{mq}->queue_declare(
- $self->{channel},
- $self->{queue_name},
- {
- passive => 0,
- durable => 1,
- exclusive => 0,
- auto_delete => 0,
- },
- );
+ my ($self) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $config = $self->config;
+
+ $self->stop();
+
+ $logger->debug(
+ 'AMQP: Connecting to RabbitMQ ' . $config->{host} . ':' . $config->{port});
+ require Net::RabbitMQ;
+ my $mq = Net::RabbitMQ->new();
+ $mq->connect(
+ $config->{host},
+ {
+ port => $config->{port},
+ user => $config->{username},
+ password => $config->{password},
+ }
+ );
+ $self->{mq} = $mq;
+
+ $logger->debug('AMQP: Opening channel ' . $self->{channel});
+ $self->{mq}->channel_open($self->{channel});
+
+ $logger->debug('AMQP: Declaring queue ' . $self->{queue_name});
+ $self->{mq}->queue_declare($self->{channel}, $self->{queue_name},
+ {passive => 0, durable => 1, exclusive => 0, auto_delete => 0,},
+ );
}
sub _bind {
- my ($self, $message) = @_;
- my $logger = Bugzilla->push_ext->logger;
- my $config = $self->config;
-
- # bind to queue (also acts to verify the connection is still valid)
- if ($self->{mq}) {
- eval {
- $logger->debug('AMQP: binding queue(' . $self->{queue_name} . ') with exchange(' . $config->{exchange} . ')');
- $self->{mq}->queue_bind(
- $self->{channel},
- $self->{queue_name},
- $config->{exchange},
- $message->routing_key,
- );
- };
- if ($@) {
- $logger->debug('AMQP: ' . clean_error($@));
- $self->{mq} = 0;
- }
+ my ($self, $message) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $config = $self->config;
+
+ # bind to queue (also acts to verify the connection is still valid)
+ if ($self->{mq}) {
+ eval {
+ $logger->debug('AMQP: binding queue('
+ . $self->{queue_name}
+ . ') with exchange('
+ . $config->{exchange}
+ . ')');
+ $self->{mq}->queue_bind(
+ $self->{channel}, $self->{queue_name},
+ $config->{exchange}, $message->routing_key,
+ );
+ };
+ if ($@) {
+ $logger->debug('AMQP: ' . clean_error($@));
+ $self->{mq} = 0;
}
+ }
}
sub should_send {
- my ($self, $message) = @_;
- my $logger = Bugzilla->push_ext->logger;
-
- my $payload = $message->payload_decoded();
- my $target = $payload->{event}->{target};
- my $is_private = $payload->{$target}->{is_private} ? 1 : 0;
- if (!$is_private && exists $payload->{$target}->{bug}) {
- $is_private = $payload->{$target}->{bug}->{is_private} ? 1 : 0;
- }
-
- if ($is_private) {
- # we only want to push the is_private message from the change_set, as
- # this is guaranteed to contain public information only
- if ($message->routing_key !~ /\.modify:is_private$/) {
- $logger->debug('AMQP: Ignoring private message');
- return 0;
- }
- $logger->debug('AMQP: Sending change of message to is_private');
+ my ($self, $message) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+
+ my $payload = $message->payload_decoded();
+ my $target = $payload->{event}->{target};
+ my $is_private = $payload->{$target}->{is_private} ? 1 : 0;
+ if (!$is_private && exists $payload->{$target}->{bug}) {
+ $is_private = $payload->{$target}->{bug}->{is_private} ? 1 : 0;
+ }
+
+ if ($is_private) {
+
+ # we only want to push the is_private message from the change_set, as
+ # this is guaranteed to contain public information only
+ if ($message->routing_key !~ /\.modify:is_private$/) {
+ $logger->debug('AMQP: Ignoring private message');
+ return 0;
}
- return 1;
+ $logger->debug('AMQP: Sending change of message to is_private');
+ }
+ return 1;
}
sub send {
- my ($self, $message) = @_;
- my $logger = Bugzilla->push_ext->logger;
- my $config = $self->config;
-
- # don't push comments to pulse
- if ($message->routing_key =~ /^comment\./) {
- $logger->debug('AMQP: Ignoring comment');
- return PUSH_RESULT_IGNORED;
- }
+ my ($self, $message) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $config = $self->config;
- # don't push private data
- $self->should_push($message)
- || return PUSH_RESULT_IGNORED;
+ # don't push comments to pulse
+ if ($message->routing_key =~ /^comment\./) {
+ $logger->debug('AMQP: Ignoring comment');
+ return PUSH_RESULT_IGNORED;
+ }
- $self->_bind($message);
+ # don't push private data
+ $self->should_push($message) || return PUSH_RESULT_IGNORED;
- eval {
- # reconnect if required
- if (!$self->{mq}) {
- $self->_connect();
- }
-
- # send message
- $logger->debug('AMQP: Publishing message');
- $self->{mq}->publish(
- $self->{channel},
- $message->routing_key,
- $message->payload,
- {
- exchange => $config->{exchange},
- },
- {
- content_type => 'text/plain',
- content_encoding => '8bit',
- },
- );
- };
- if ($@) {
- return (PUSH_RESULT_TRANSIENT, clean_error($@));
+ $self->_bind($message);
+
+ eval {
+ # reconnect if required
+ if (!$self->{mq}) {
+ $self->_connect();
}
- return PUSH_RESULT_OK;
+ # send message
+ $logger->debug('AMQP: Publishing message');
+ $self->{mq}->publish(
+ $self->{channel}, $message->routing_key, $message->payload,
+ {exchange => $config->{exchange},},
+ {content_type => 'text/plain', content_encoding => '8bit',},
+ );
+ };
+ if ($@) {
+ return (PUSH_RESULT_TRANSIENT, clean_error($@));
+ }
+
+ return PUSH_RESULT_OK;
}
1;
diff --git a/extensions/Push/lib/Connector.disabled/ServiceNow.pm b/extensions/Push/lib/Connector.disabled/ServiceNow.pm
index d0ebdcf10..032e47dde 100644
--- a/extensions/Push/lib/Connector.disabled/ServiceNow.pm
+++ b/extensions/Push/lib/Connector.disabled/ServiceNow.pm
@@ -32,403 +32,411 @@ use MIME::Base64;
use Net::LDAP;
use constant SEND_COMPONENTS => (
- {
- product => 'mozilla.org',
- component => 'Server Operations: Desktop Issues',
- },
+ {product => 'mozilla.org', component => 'Server Operations: Desktop Issues',},
);
sub options {
- return (
- {
- name => 'bugzilla_user',
- label => 'Bugzilla Service-Now User',
- type => 'string',
- default => 'service.now@bugzilla.tld',
- required => 1,
- validate => sub {
- Bugzilla::User->new({ name => $_[0] })
- || die "Invalid Bugzilla user ($_[0])\n";
- },
- },
- {
- name => 'ldap_scheme',
- label => 'Mozilla LDAP Scheme',
- type => 'select',
- values => [ 'LDAP', 'LDAPS' ],
- default => 'LDAPS',
- required => 1,
- },
- {
- name => 'ldap_host',
- label => 'Mozilla LDAP Host',
- type => 'string',
- default => '',
- required => 1,
- },
- {
- name => 'ldap_user',
- label => 'Mozilla LDAP Bind Username',
- type => 'string',
- default => '',
- required => 1,
- },
- {
- name => 'ldap_pass',
- label => 'Mozilla LDAP Password',
- type => 'password',
- default => '',
- required => 1,
- },
- {
- name => 'ldap_poll',
- label => 'Mozilla LDAP Poll Frequency',
- type => 'string',
- default => '3',
- required => 1,
- help => 'minutes',
- validate => sub {
- $_[0] =~ /\D/
- && die "LDAP Poll Frequency must be an integer\n";
- $_[0] == 0
- && die "LDAP Poll Frequency cannot be less than one minute\n";
- },
- },
- {
- name => 'service_now_url',
- label => 'Service Now JSON URL',
- type => 'string',
- default => 'https://mozilladev.service-now.com',
- required => 1,
- help => "Must start with https:// and end with ?JSON",
- validate => sub {
- $_[0] =~ m#^https://[^\.\/]+\.service-now\.com\/#
- || die "Invalid Service Now JSON URL\n";
- $_[0] =~ m#\?JSON$#
- || die "Invalid Service Now JSON URL (must end with ?JSON)\n";
- },
- },
- {
- name => 'service_now_user',
- label => 'Service Now JSON Username',
- type => 'string',
- default => '',
- required => 1,
- },
- {
- name => 'service_now_pass',
- label => 'Service Now JSON Password',
- type => 'password',
- default => '',
- required => 1,
- },
- );
+ return (
+ {
+ name => 'bugzilla_user',
+ label => 'Bugzilla Service-Now User',
+ type => 'string',
+ default => 'service.now@bugzilla.tld',
+ required => 1,
+ validate => sub {
+ Bugzilla::User->new({name => $_[0]}) || die "Invalid Bugzilla user ($_[0])\n";
+ },
+ },
+ {
+ name => 'ldap_scheme',
+ label => 'Mozilla LDAP Scheme',
+ type => 'select',
+ values => ['LDAP', 'LDAPS'],
+ default => 'LDAPS',
+ required => 1,
+ },
+ {
+ name => 'ldap_host',
+ label => 'Mozilla LDAP Host',
+ type => 'string',
+ default => '',
+ required => 1,
+ },
+ {
+ name => 'ldap_user',
+ label => 'Mozilla LDAP Bind Username',
+ type => 'string',
+ default => '',
+ required => 1,
+ },
+ {
+ name => 'ldap_pass',
+ label => 'Mozilla LDAP Password',
+ type => 'password',
+ default => '',
+ required => 1,
+ },
+ {
+ name => 'ldap_poll',
+ label => 'Mozilla LDAP Poll Frequency',
+ type => 'string',
+ default => '3',
+ required => 1,
+ help => 'minutes',
+ validate => sub {
+ $_[0] =~ /\D/ && die "LDAP Poll Frequency must be an integer\n";
+ $_[0] == 0 && die "LDAP Poll Frequency cannot be less than one minute\n";
+ },
+ },
+ {
+ name => 'service_now_url',
+ label => 'Service Now JSON URL',
+ type => 'string',
+ default => 'https://mozilladev.service-now.com',
+ required => 1,
+ help => "Must start with https:// and end with ?JSON",
+ validate => sub {
+ $_[0] =~ m#^https://[^\.\/]+\.service-now\.com\/#
+ || die "Invalid Service Now JSON URL\n";
+ $_[0] =~ m#\?JSON$#
+ || die "Invalid Service Now JSON URL (must end with ?JSON)\n";
+ },
+ },
+ {
+ name => 'service_now_user',
+ label => 'Service Now JSON Username',
+ type => 'string',
+ default => '',
+ required => 1,
+ },
+ {
+ name => 'service_now_pass',
+ label => 'Service Now JSON Password',
+ type => 'password',
+ default => '',
+ required => 1,
+ },
+ );
}
sub options_validate {
- my ($self, $config) = @_;
- my $host = $config->{ldap_host};
- trick_taint($host);
- my $scheme = lc($config->{ldap_scheme});
- eval {
- my $ldap = Net::LDAP->new($host, scheme => $scheme, onerror => 'die', timeout => 5)
- or die $!;
- $ldap->bind($config->{ldap_user}, password => $config->{ldap_pass});
- };
- if ($@) {
- die sprintf("Failed to connect to %s://%s/: %s\n", $scheme, $host, $@);
- }
+ my ($self, $config) = @_;
+ my $host = $config->{ldap_host};
+ trick_taint($host);
+ my $scheme = lc($config->{ldap_scheme});
+ eval {
+ my $ldap
+ = Net::LDAP->new($host, scheme => $scheme, onerror => 'die', timeout => 5)
+ or die $!;
+ $ldap->bind($config->{ldap_user}, password => $config->{ldap_pass});
+ };
+ if ($@) {
+ die sprintf("Failed to connect to %s://%s/: %s\n", $scheme, $host, $@);
+ }
}
my $_instance;
sub init {
- my ($self) = @_;
- $_instance = $self;
+ my ($self) = @_;
+ $_instance = $self;
}
sub load_config {
- my ($self) = @_;
- $self->SUPER::load_config(@_);
- $self->{bugzilla_user} ||= Bugzilla::User->new({ name => $self->config->{bugzilla_user} });
+ my ($self) = @_;
+ $self->SUPER::load_config(@_);
+ $self->{bugzilla_user}
+ ||= Bugzilla::User->new({name => $self->config->{bugzilla_user}});
}
sub should_send {
- my ($self, $message) = @_;
-
- my $data = $message->payload_decoded;
- my $bug_data = $self->_get_bug_data($data)
- || return 0;
-
- # we don't want to send the initial comment in a separate message
- # because we inject it into the inital message
- if (exists $data->{comment} && $data->{comment}->{number} == 0) {
- return 0;
- }
-
- my $target = $data->{event}->{target};
- unless ($target eq 'bug' || $target eq 'comment' || $target eq 'attachment') {
- return 0;
- }
-
- # ensure the service-now user can see the bug
- if (!$self->{bugzilla_user} || !$self->{bugzilla_user}->is_enabled) {
- return 0;
- }
- $self->{bugzilla_user}->can_see_bug($bug_data->{id})
- || return 0;
-
- # don't push changes made by the service-now account
- $data->{event}->{user}->{id} == $self->{bugzilla_user}->id
- && return 0;
-
- # filter based on the component
- my $bug = Bugzilla::Bug->new($bug_data->{id});
- my $send = 0;
- foreach my $rh (SEND_COMPONENTS) {
- if ($bug->product eq $rh->{product} && $bug->component eq $rh->{component}) {
- $send = 1;
- last;
- }
+ my ($self, $message) = @_;
+
+ my $data = $message->payload_decoded;
+ my $bug_data = $self->_get_bug_data($data) || return 0;
+
+ # we don't want to send the initial comment in a separate message
+ # because we inject it into the inital message
+ if (exists $data->{comment} && $data->{comment}->{number} == 0) {
+ return 0;
+ }
+
+ my $target = $data->{event}->{target};
+ unless ($target eq 'bug' || $target eq 'comment' || $target eq 'attachment') {
+ return 0;
+ }
+
+ # ensure the service-now user can see the bug
+ if (!$self->{bugzilla_user} || !$self->{bugzilla_user}->is_enabled) {
+ return 0;
+ }
+ $self->{bugzilla_user}->can_see_bug($bug_data->{id}) || return 0;
+
+ # don't push changes made by the service-now account
+ $data->{event}->{user}->{id} == $self->{bugzilla_user}->id && return 0;
+
+ # filter based on the component
+ my $bug = Bugzilla::Bug->new($bug_data->{id});
+ my $send = 0;
+ foreach my $rh (SEND_COMPONENTS) {
+ if ($bug->product eq $rh->{product} && $bug->component eq $rh->{component}) {
+ $send = 1;
+ last;
}
- return $send;
+ }
+ return $send;
}
sub send {
- my ($self, $message) = @_;
- my $logger = Bugzilla->push_ext->logger;
- my $config = $self->config;
-
- # should_send intiailises bugzilla_user; make sure we return a useful error message
- if (!$self->{bugzilla_user}) {
- return (PUSH_RESULT_TRANSIENT, "Invalid bugzilla-user (" . $self->config->{bugzilla_user} . ")");
- }
-
- # load the bug
- my $data = $message->payload_decoded;
- my $bug_data = $self->_get_bug_data($data);
- my $bug = Bugzilla::Bug->new($bug_data->{id});
-
- if ($message->routing_key eq 'bug.create') {
- # inject the comment into the data for new bugs
- my $comment = shift @{ $bug->comments };
- if ($comment->body ne '') {
- $bug_data->{comment} = Bugzilla::Extension::Push::Serialise->instance->object_to_hash($comment, 1);
- }
-
- } elsif ($message->routing_key eq 'attachment.create') {
- # inject the attachment payload
- my $attachment = Bugzilla::Attachment->new($data->{attachment}->{id});
- $data->{attachment}->{data} = encode_base64($attachment->data);
- }
-
- # map bmo login to ldap login and insert into json payload
- $self->_add_ldap_logins($data, {});
-
- # flatten json data
- $self->_flatten($data);
-
- # add sysparm_action
- $data->{sysparm_action} = 'insert';
-
- if ($logger->debugging) {
- $logger->debug(to_json(ref($data) ? $data : from_json($data), 1));
- }
-
- # send to service-now
- my $request = HTTP::Request->new(POST => $self->config->{service_now_url});
- $request->content_type('application/json');
- $request->content(to_json($data));
- $request->authorization_basic($self->config->{service_now_user}, $self->config->{service_now_pass});
-
- $self->{lwp} ||= LWP::UserAgent->new(agent => Bugzilla->localconfig->{urlbase});
- my $result = $self->{lwp}->request($request);
-
- # http level errors
- if (!$result->is_success) {
- # treat these as transient
- return (PUSH_RESULT_TRANSIENT, $result->status_line);
- }
-
- # empty response
- if (length($result->content) == 0) {
- # malformed request, treat as transient to allow code to fix
- # may also be misconfiguration on servicenow, also transient
- return (PUSH_RESULT_TRANSIENT, "Empty response");
+ my ($self, $message) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $config = $self->config;
+
+# should_send intiailises bugzilla_user; make sure we return a useful error message
+ if (!$self->{bugzilla_user}) {
+ return (PUSH_RESULT_TRANSIENT,
+ "Invalid bugzilla-user (" . $self->config->{bugzilla_user} . ")");
+ }
+
+ # load the bug
+ my $data = $message->payload_decoded;
+ my $bug_data = $self->_get_bug_data($data);
+ my $bug = Bugzilla::Bug->new($bug_data->{id});
+
+ if ($message->routing_key eq 'bug.create') {
+
+ # inject the comment into the data for new bugs
+ my $comment = shift @{$bug->comments};
+ if ($comment->body ne '') {
+ $bug_data->{comment}
+ = Bugzilla::Extension::Push::Serialise->instance->object_to_hash($comment, 1);
}
- # json errors
- my $result_data;
- eval {
- $result_data = from_json($result->content);
- };
- if ($@) {
- return (PUSH_RESULT_TRANSIENT, clean_error($@));
- }
- if ($logger->debugging) {
- $logger->debug(to_json($result_data, 1));
- }
- if (exists $result_data->{error}) {
- return (PUSH_RESULT_ERROR, $result_data->{error});
- };
-
- # malformed/unexpected json response
- if (!exists $result_data->{records}
- || ref($result_data->{records}) ne 'ARRAY'
- || scalar(@{$result_data->{records}}) == 0
- ) {
- return (PUSH_RESULT_ERROR, "Malformed JSON response from ServiceNow: missing or empty 'records' array");
- }
-
- my $record = $result_data->{records}->[0];
- if (ref($record) ne 'HASH') {
- return (PUSH_RESULT_ERROR, "Malformed JSON response from ServiceNow: 'records' array does not contain an object");
- }
+ }
+ elsif ($message->routing_key eq 'attachment.create') {
+
+ # inject the attachment payload
+ my $attachment = Bugzilla::Attachment->new($data->{attachment}->{id});
+ $data->{attachment}->{data} = encode_base64($attachment->data);
+ }
+
+ # map bmo login to ldap login and insert into json payload
+ $self->_add_ldap_logins($data, {});
+
+ # flatten json data
+ $self->_flatten($data);
+
+ # add sysparm_action
+ $data->{sysparm_action} = 'insert';
+
+ if ($logger->debugging) {
+ $logger->debug(to_json(ref($data) ? $data : from_json($data), 1));
+ }
+
+ # send to service-now
+ my $request = HTTP::Request->new(POST => $self->config->{service_now_url});
+ $request->content_type('application/json');
+ $request->content(to_json($data));
+ $request->authorization_basic($self->config->{service_now_user},
+ $self->config->{service_now_pass});
+
+ $self->{lwp} ||= LWP::UserAgent->new(agent => Bugzilla->localconfig->{urlbase});
+ my $result = $self->{lwp}->request($request);
+
+ # http level errors
+ if (!$result->is_success) {
+
+ # treat these as transient
+ return (PUSH_RESULT_TRANSIENT, $result->status_line);
+ }
+
+ # empty response
+ if (length($result->content) == 0) {
+
+ # malformed request, treat as transient to allow code to fix
+ # may also be misconfiguration on servicenow, also transient
+ return (PUSH_RESULT_TRANSIENT, "Empty response");
+ }
+
+ # json errors
+ my $result_data;
+ eval { $result_data = from_json($result->content); };
+ if ($@) {
+ return (PUSH_RESULT_TRANSIENT, clean_error($@));
+ }
+ if ($logger->debugging) {
+ $logger->debug(to_json($result_data, 1));
+ }
+ if (exists $result_data->{error}) {
+ return (PUSH_RESULT_ERROR, $result_data->{error});
+ }
+
+ # malformed/unexpected json response
+ if (!exists $result_data->{records}
+ || ref($result_data->{records}) ne 'ARRAY'
+ || scalar(@{$result_data->{records}}) == 0)
+ {
+ return (PUSH_RESULT_ERROR,
+ "Malformed JSON response from ServiceNow: missing or empty 'records' array");
+ }
+
+ my $record = $result_data->{records}->[0];
+ if (ref($record) ne 'HASH') {
+ return (PUSH_RESULT_ERROR,
+ "Malformed JSON response from ServiceNow: 'records' array does not contain an object"
+ );
+ }
- # sys_id is the unique identifier for this action
- if (!exists $record->{sys_id} || $record->{sys_id} eq '') {
- return (PUSH_RESULT_ERROR, "Malformed JSON response from ServiceNow: 'records object' does not contain a valid sys_id");
- }
+ # sys_id is the unique identifier for this action
+ if (!exists $record->{sys_id} || $record->{sys_id} eq '') {
+ return (PUSH_RESULT_ERROR,
+ "Malformed JSON response from ServiceNow: 'records object' does not contain a valid sys_id"
+ );
+ }
- # success
- return (PUSH_RESULT_OK, "sys_id: " . $record->{sys_id});
+ # success
+ return (PUSH_RESULT_OK, "sys_id: " . $record->{sys_id});
}
sub _get_bug_data {
- my ($self, $data) = @_;
- my $target = $data->{event}->{target};
- if ($target eq 'bug') {
- return $data->{bug};
- } elsif (exists $data->{$target}->{bug}) {
- return $data->{$target}->{bug};
- } else {
- return;
- }
+ my ($self, $data) = @_;
+ my $target = $data->{event}->{target};
+ if ($target eq 'bug') {
+ return $data->{bug};
+ }
+ elsif (exists $data->{$target}->{bug}) {
+ return $data->{$target}->{bug};
+ }
+ else {
+ return;
+ }
}
sub _flatten {
- # service-now expects a flat json object
- my ($self, $data) = @_;
- my $target = $data->{event}->{target};
+ # service-now expects a flat json object
+ my ($self, $data) = @_;
- # delete unnecessary deep objects
- if ($target eq 'comment' || $target eq 'attachment') {
- $data->{$target}->{bug_id} = $data->{$target}->{bug}->{id};
- delete $data->{$target}->{bug};
- }
- delete $data->{event}->{changes};
+ my $target = $data->{event}->{target};
- $self->_flatten_hash($data, $data, 'u');
+ # delete unnecessary deep objects
+ if ($target eq 'comment' || $target eq 'attachment') {
+ $data->{$target}->{bug_id} = $data->{$target}->{bug}->{id};
+ delete $data->{$target}->{bug};
+ }
+ delete $data->{event}->{changes};
+
+ $self->_flatten_hash($data, $data, 'u');
}
sub _flatten_hash {
- my ($self, $base_hash, $hash, $prefix) = @_;
- foreach my $key (keys %$hash) {
- if (ref($hash->{$key}) eq 'HASH') {
- $self->_flatten_hash($base_hash, $hash->{$key}, $prefix . "_$key");
- } elsif (ref($hash->{$key}) ne 'ARRAY') {
- $base_hash->{$prefix . "_$key"} = $hash->{$key};
- }
- delete $hash->{$key};
+ my ($self, $base_hash, $hash, $prefix) = @_;
+ foreach my $key (keys %$hash) {
+ if (ref($hash->{$key}) eq 'HASH') {
+ $self->_flatten_hash($base_hash, $hash->{$key}, $prefix . "_$key");
+ }
+ elsif (ref($hash->{$key}) ne 'ARRAY') {
+ $base_hash->{$prefix . "_$key"} = $hash->{$key};
}
+ delete $hash->{$key};
+ }
}
sub _add_ldap_logins {
- my ($self, $rh, $cache) = @_;
- if (exists $rh->{login}) {
- my $login = $rh->{login};
- $cache->{$login} ||= $self->_bmo_to_ldap($login);
- Bugzilla->push_ext->logger->debug("BMO($login) --> LDAP(" . $cache->{$login} . ")");
- $rh->{ldap} = $cache->{$login};
- }
- foreach my $key (keys %$rh) {
- next unless ref($rh->{$key}) eq 'HASH';
- $self->_add_ldap_logins($rh->{$key}, $cache);
- }
+ my ($self, $rh, $cache) = @_;
+ if (exists $rh->{login}) {
+ my $login = $rh->{login};
+ $cache->{$login} ||= $self->_bmo_to_ldap($login);
+ Bugzilla->push_ext->logger->debug(
+ "BMO($login) --> LDAP(" . $cache->{$login} . ")");
+ $rh->{ldap} = $cache->{$login};
+ }
+ foreach my $key (keys %$rh) {
+ next unless ref($rh->{$key}) eq 'HASH';
+ $self->_add_ldap_logins($rh->{$key}, $cache);
+ }
}
sub _bmo_to_ldap {
- my ($self, $login) = @_;
- my $ldap = $self->_ldap_cache();
+ my ($self, $login) = @_;
+ my $ldap = $self->_ldap_cache();
- return '' unless $login =~ /\@mozilla\.(?:com|org)$/;
+ return '' unless $login =~ /\@mozilla\.(?:com|org)$/;
- foreach my $check ($login, canon_email($login)) {
- # check for matching bugmail entry
- foreach my $mail (keys %$ldap) {
- next unless $ldap->{$mail}{bugmail_canon} eq $check;
- return $mail;
- }
+ foreach my $check ($login, canon_email($login)) {
- # check for matching mail
- if (exists $ldap->{$check}) {
- return $check;
- }
+ # check for matching bugmail entry
+ foreach my $mail (keys %$ldap) {
+ next unless $ldap->{$mail}{bugmail_canon} eq $check;
+ return $mail;
+ }
- # check for matching email alias
- foreach my $mail (sort keys %$ldap) {
- next unless grep { $check eq $_ } @{$ldap->{$mail}{aliases}};
- return $mail;
- }
+ # check for matching mail
+ if (exists $ldap->{$check}) {
+ return $check;
+ }
+
+ # check for matching email alias
+ foreach my $mail (sort keys %$ldap) {
+ next unless grep { $check eq $_ } @{$ldap->{$mail}{aliases}};
+ return $mail;
}
+ }
- return '';
+ return '';
}
sub _ldap_cache {
- my ($self) = @_;
- my $logger = Bugzilla->push_ext->logger;
- my $config = $self->config;
-
- # cache of all ldap entries; updated infrequently
- if (!$self->{ldap_cache_time} || (time) - $self->{ldap_cache_time} > $config->{ldap_poll} * 60) {
- $logger->debug('refreshing LDAP cache');
-
- my $cache = {};
-
- my $host = $config->{ldap_host};
- trick_taint($host);
- my $scheme = lc($config->{ldap_scheme});
- my $ldap = Net::LDAP->new($host, scheme => $scheme, onerror => 'die')
- or die $!;
- $ldap->bind($config->{ldap_user}, password => $config->{ldap_pass});
- foreach my $ldap_base ('o=com,dc=mozilla', 'o=org,dc=mozilla') {
- my $result = $ldap->search(
- base => $ldap_base,
- scope => 'sub',
- filter => '(mail=*)',
- attrs => ['mail', 'bugzillaEmail', 'emailAlias', 'cn', 'employeeType'],
- );
- foreach my $entry ($result->entries) {
- my ($name, $bugMail, $mail, $type) =
- map { $entry->get_value($_) || '' }
- qw(cn bugzillaEmail mail employeeType);
- next if $type eq 'DISABLED';
- $mail = lc $mail;
- $bugMail = '' if $bugMail !~ /\@/;
- $bugMail = trim($bugMail);
- if ($bugMail =~ / /) {
- $bugMail = (grep { /\@/ } split / /, $bugMail)[0];
- }
- $name =~ s/\s+/ /g;
- $cache->{$mail}{name} = trim($name);
- $cache->{$mail}{bugmail} = $bugMail;
- $cache->{$mail}{bugmail_canon} = canon_email($bugMail);
- $cache->{$mail}{aliases} = [];
- foreach my $alias (
- @{$entry->get_value('emailAlias', asref => 1) || []}
- ) {
- push @{$cache->{$mail}{aliases}}, canon_email($alias);
- }
- }
- }
+ my ($self) = @_;
+ my $logger = Bugzilla->push_ext->logger;
+ my $config = $self->config;
+
+ # cache of all ldap entries; updated infrequently
+ if (!$self->{ldap_cache_time}
+ || (time) - $self->{ldap_cache_time} > $config->{ldap_poll} * 60)
+ {
+ $logger->debug('refreshing LDAP cache');
- $self->{ldap_cache} = $cache;
- $self->{ldap_cache_time} = (time);
+ my $cache = {};
+
+ my $host = $config->{ldap_host};
+ trick_taint($host);
+ my $scheme = lc($config->{ldap_scheme});
+ my $ldap = Net::LDAP->new($host, scheme => $scheme, onerror => 'die') or die $!;
+ $ldap->bind($config->{ldap_user}, password => $config->{ldap_pass});
+ foreach my $ldap_base ('o=com,dc=mozilla', 'o=org,dc=mozilla') {
+ my $result = $ldap->search(
+ base => $ldap_base,
+ scope => 'sub',
+ filter => '(mail=*)',
+ attrs => ['mail', 'bugzillaEmail', 'emailAlias', 'cn', 'employeeType'],
+ );
+ foreach my $entry ($result->entries) {
+ my ($name, $bugMail, $mail, $type)
+ = map { $entry->get_value($_) || '' } qw(cn bugzillaEmail mail employeeType);
+ next if $type eq 'DISABLED';
+ $mail = lc $mail;
+ $bugMail = '' if $bugMail !~ /\@/;
+ $bugMail = trim($bugMail);
+ if ($bugMail =~ / /) {
+ $bugMail = (grep {/\@/} split / /, $bugMail)[0];
+ }
+ $name =~ s/\s+/ /g;
+ $cache->{$mail}{name} = trim($name);
+ $cache->{$mail}{bugmail} = $bugMail;
+ $cache->{$mail}{bugmail_canon} = canon_email($bugMail);
+ $cache->{$mail}{aliases} = [];
+ foreach my $alias (@{$entry->get_value('emailAlias', asref => 1) || []}) {
+ push @{$cache->{$mail}{aliases}}, canon_email($alias);
+ }
+ }
}
- return $self->{ldap_cache};
+ $self->{ldap_cache} = $cache;
+ $self->{ldap_cache_time} = (time);
+ }
+
+ return $self->{ldap_cache};
}
1;