{"action":"created","comment":{"url":"https://api.github.com/repos/os-autoinst/openQA/pulls/comments/89486806","pull_request_review_id":10030903,"id":89486806,"diff_hunk":"@@ -0,0 +1,182 @@\n+# Copyright (C) 2016 SUSE Linux GmbH\n+#\n+# This program is free software; you can redistribute it and/or modify\n+# it under the terms of the GNU General Public License as published by\n+# the Free Software Foundation; either version 2 of the License, or\n+# (at your option) any later version.\n+#\n+# This program is distributed in the hope that it will be useful,\n+# but WITHOUT ANY WARRANTY; without even the implied warranty of\n+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+# GNU General Public License for more details.\n+#\n+# You should have received a copy of the GNU General Public License along\n+# with this program; if not, see <http://www.gnu.org/licenses/>.\n+\n+package OpenQA::WebAPI::Plugin::AMQP;\n+\n+use strict;\n+use warnings;\n+\n+use parent qw/Mojolicious::Plugin/;\n+use JSON;\n+use Mojo::IOLoop;\n+use OpenQA::Utils;\n+use OpenQA::Schema::Result::Jobs;\n+use Mojo::RabbitMQ::Client;\n+\n+my $app;\n+my $config;\n+my $client;\n+my $channel;\n+my $reconnecting = 0;\n+\n+my @job_events     = qw/job_create job_delete job_cancel job_duplicate job_restart job_update_result job_done/;\n+my @comment_events = qw/comment_create comment_update comment_delete/;\n+\n+sub reconnect {\n+    my $self = shift;\n+\n+    return if $reconnecting;\n+    $reconnecting = 1;\n+    Mojo::IOLoop->timer(\n+        5 => sub {\n+            $reconnecting = 0;\n+            $self->connect();\n+        });\n+}\n+\n+sub connect {\n+    my $self = shift;\n+\n+    OpenQA::Utils::log_debug(\"Connecting to AMQP server\");\n+    $config = $app->config;\n+    $client = Mojo::RabbitMQ::Client->new(url => $config->{amqp}{url});\n+    $client->catch(sub { OpenQA::Utils::log_warning(\"Failed to connect to AMQP server: \" . $config->{amqp}{url}); });\n+    $client->on(\n+        open => sub {\n+            my ($client) = @_;\n+\n+            $channel = Mojo::RabbitMQ::Channel->new();\n+            $channel->catch(sub { OpenQA::Utils::log_warning(\"Error on AMQP channel received\"); });\n+\n+            $channel->on(\n+                open => sub {\n+                    my ($channel) = @_;\n+                    $channel->declare_exchange(exchange => $config->{amqp}{exchange}, type => 'topic')->deliver();\n+                });\n+            $channel->on(\n+                close => sub {\n+                    OpenQA::Utils::log_warning(\"AMQP channel closed\");\n+                });\n+            $client->open_channel($channel);\n+        });\n+    $client->on(\n+        close => sub {\n+            OpenQA::Utils::log_warning(\"AMQP connection closed\");\n+            $self->reconnect();\n+        });\n+    $client->on(\n+        error => sub {\n+            OpenQA::Utils::log_warning(\"AMQP connection error\");\n+            $self->reconnect();\n+        });\n+    $client->on(\n+        disconnect => sub {\n+            OpenQA::Utils::log_warning(\"AMQP connection closed\");\n+            $self->reconnect();\n+        });\n+    $client->on(\n+        timeout => sub {\n+            OpenQA::Utils::log_warning(\"AMQP connection closed\");\n+            $self->reconnect();\n+        });\n+    $client->connect();\n+}\n+\n+sub register {\n+    my $self = shift;\n+    $app = shift;\n+    my $reactor = Mojo::IOLoop->singleton;\n+\n+    $self->connect();\n+\n+    # register for events\n+    for my $e (@job_events) {\n+        $reactor->on(\"openqa_$e\" => sub { shift; $self->on_job_event($app, @_) });\n+    }\n+    for my $e (@comment_events) {\n+        $reactor->on(\"openqa_$e\" => sub { shift; $self->on_comment_event($app, @_) });\n+    }\n+}\n+\n+sub log_event {\n+    my ($event, $event_data) = @_;\n+\n+    unless ($channel && $channel->is_open) {\n+        OpenQA::Utils::log_warning(\"Error sending AMQP event: Channel is not open\");\n+        return;\n+    }\n+\n+    # use dot separators\n+    $event =~ s/_/\\./;\n+    $event =~ s/_/\\./;\n+\n+    my $topic = $config->{amqp}{topic_prefix} . '.' . $event;\n+\n+    # convert data to JSON, with reliable key ordering (helps the tests)\n+    $event_data = to_json($event_data, {canonical => 1, allow_blessed => 1});\n+\n+    OpenQA::Utils::log_debug(\"Sending AMQP event: $topic\");\n+\n+    $channel->publish(\n+        exchange    => $config->{amqp}{exchange},\n+        routing_key => $topic,\n+        body        => $event_data\n+    )->deliver();\n+}\n+\n+sub on_job_event {\n+    my ($self, $app, $args) = @_;\n+    my ($user_id, $connection_id, $event, $event_data) = @$args;\n+\n+    # find count of pending jobs for the same build\n+    # this is so we can tell when all tests for a build are done\n+    my $job = $app->db->resultset('Jobs')->find({id => $event_data->{id}});\n+    my $build = $job->BUILD;\n+    $event_data->{group_id}  = $job->group_id;\n+    $event_data->{remaining} = $app->db->resultset('Jobs')->search(\n+        {\n+            'me.BUILD' => $build,\n+            state      => [OpenQA::Schema::Result::Jobs::PENDING_STATES],\n+        })->count;\n+    # add various useful properties for consumers if not there already\n+    $event_data->{BUILD}   //= $build;\n+    $event_data->{TEST}    //= $job->TEST;\n+    $event_data->{ARCH}    //= $job->ARCH;\n+    $event_data->{MACHINE} //= $job->MACHINE;\n+    $event_data->{FLAVOR}  //= $job->FLAVOR;\n+    $event_data->{ISO}     //= $job->settings_hash->{ISO} if ($job->settings_hash->{ISO});","path":"lib/OpenQA/WebAPI/Plugin/AMQP.pm","position":159,"original_position":159,"commit_id":"917bf81bb11f25eac1d9588d4124114ec87c51a4","original_commit_id":"917bf81bb11f25eac1d9588d4124114ec87c51a4","user":{"login":"coolo","id":1067203,"avatar_url":"https://avatars.githubusercontent.com/u/1067203?v=3","gravatar_id":"","url":"https://api.github.com/users/coolo","html_url":"https://github.com/coolo","followers_url":"https://api.github.com/users/coolo/followers","following_url":"https://api.github.com/users/coolo/following{/other_user}","gists_url":"https://api.github.com/users/coolo/gists{/gist_id}","starred_url":"https://api.github.com/users/coolo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/coolo/subscriptions","organizations_url":"https://api.github.com/users/coolo/orgs","repos_url":"https://api.github.com/users/coolo/repos","events_url":"https://api.github.com/users/coolo/events{/privacy}","received_events_url":"https://api.github.com/users/coolo/received_events","type":"User","site_admin":false},"body":"please use a loop and don't duplicate","created_at":"2016-11-24T12:14:34Z","updated_at":"2016-11-24T12:15:58Z","html_url":"https://github.com/os-autoinst/openQA/pull/1032#discussion_r89486806","pull_request_url":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032","_links":{"self":{"href":"https://api.github.com/repos/os-autoinst/openQA/pulls/comments/89486806"},"html":{"href":"https://github.com/os-autoinst/openQA/pull/1032#discussion_r89486806"},"pull_request":{"href":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032"}}},"pull_request":{"url":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032","id":95000433,"html_url":"https://github.com/os-autoinst/openQA/pull/1032","diff_url":"https://github.com/os-autoinst/openQA/pull/1032.diff","patch_url":"https://github.com/os-autoinst/openQA/pull/1032.patch","issue_url":"https://api.github.com/repos/os-autoinst/openQA/issues/1032","number":1032,"state":"open","locked":false,"title":"Add RabbitMQ support","user":{"login":"asdil12","id":725608,"avatar_url":"https://avatars.githubusercontent.com/u/725608?v=3","gravatar_id":"","url":"https://api.github.com/users/asdil12","html_url":"https://github.com/asdil12","followers_url":"https://api.github.com/users/asdil12/followers","following_url":"https://api.github.com/users/asdil12/following{/other_user}","gists_url":"https://api.github.com/users/asdil12/gists{/gist_id}","starred_url":"https://api.github.com/users/asdil12/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asdil12/subscriptions","organizations_url":"https://api.github.com/users/asdil12/orgs","repos_url":"https://api.github.com/users/asdil12/repos","events_url":"https://api.github.com/users/asdil12/events{/privacy}","received_events_url":"https://api.github.com/users/asdil12/received_events","type":"User","site_admin":false},"body":"This will add a plugin to send the events via AMQP (RabbitMQ).\r\nThe plugin depends on `Mojo::RabbitMQ::Client`.\r\n\r\n@AdamWill: We did some changes on the comment event names.\r\n\r\nThe PR also has some fixes for problems with `comment->hash` that were hidden by the too friendly mojo internal json encoder.\r\nAlso the `jobs_reset` event was removed (it was broken in the Fedmsg plugin anyway) and replaced by multiple `job_reset` events. This removes some edge cases that violated the `object.action` event name pattern. Sticking to that pattern allows easy rabbitmq serverside event filtering.","created_at":"2016-11-23T13:13:06Z","updated_at":"2016-11-24T12:15:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a40401475bb7425cbf0485bb7f0cb2bd8cd64c28","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032/commits","review_comments_url":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032/comments","review_comment_url":"https://api.github.com/repos/os-autoinst/openQA/pulls/comments{/number}","comments_url":"https://api.github.com/repos/os-autoinst/openQA/issues/1032/comments","statuses_url":"https://api.github.com/repos/os-autoinst/openQA/statuses/917bf81bb11f25eac1d9588d4124114ec87c51a4","head":{"label":"asdil12:amqp","ref":"amqp","sha":"917bf81bb11f25eac1d9588d4124114ec87c51a4","user":{"login":"asdil12","id":725608,"avatar_url":"https://avatars.githubusercontent.com/u/725608?v=3","gravatar_id":"","url":"https://api.github.com/users/asdil12","html_url":"https://github.com/asdil12","followers_url":"https://api.github.com/users/asdil12/followers","following_url":"https://api.github.com/users/asdil12/following{/other_user}","gists_url":"https://api.github.com/users/asdil12/gists{/gist_id}","starred_url":"https://api.github.com/users/asdil12/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asdil12/subscriptions","organizations_url":"https://api.github.com/users/asdil12/orgs","repos_url":"https://api.github.com/users/asdil12/repos","events_url":"https://api.github.com/users/asdil12/events{/privacy}","received_events_url":"https://api.github.com/users/asdil12/received_events","type":"User","site_admin":false},"repo":{"id":34267921,"name":"openQA","full_name":"asdil12/openQA","owner":{"login":"asdil12","id":725608,"avatar_url":"https://avatars.githubusercontent.com/u/725608?v=3","gravatar_id":"","url":"https://api.github.com/users/asdil12","html_url":"https://github.com/asdil12","followers_url":"https://api.github.com/users/asdil12/followers","following_url":"https://api.github.com/users/asdil12/following{/other_user}","gists_url":"https://api.github.com/users/asdil12/gists{/gist_id}","starred_url":"https://api.github.com/users/asdil12/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asdil12/subscriptions","organizations_url":"https://api.github.com/users/asdil12/orgs","repos_url":"https://api.github.com/users/asdil12/repos","events_url":"https://api.github.com/users/asdil12/events{/privacy}","received_events_url":"https://api.github.com/users/asdil12/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/asdil12/openQA","description":"openQA web-frontend, scheduler and tools","fork":true,"url":"https://api.github.com/repos/asdil12/openQA","forks_url":"https://api.github.com/repos/asdil12/openQA/forks","keys_url":"https://api.github.com/repos/asdil12/openQA/keys{/key_id}","collaborators_url":"https://api.github.com/repos/asdil12/openQA/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/asdil12/openQA/teams","hooks_url":"https://api.github.com/repos/asdil12/openQA/hooks","issue_events_url":"https://api.github.com/repos/asdil12/openQA/issues/events{/number}","events_url":"https://api.github.com/repos/asdil12/openQA/events","assignees_url":"https://api.github.com/repos/asdil12/openQA/assignees{/user}","branches_url":"https://api.github.com/repos/asdil12/openQA/branches{/branch}","tags_url":"https://api.github.com/repos/asdil12/openQA/tags","blobs_url":"https://api.github.com/repos/asdil12/openQA/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/asdil12/openQA/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/asdil12/openQA/git/refs{/sha}","trees_url":"https://api.github.com/repos/asdil12/openQA/git/trees{/sha}","statuses_url":"https://api.github.com/repos/asdil12/openQA/statuses/{sha}","languages_url":"https://api.github.com/repos/asdil12/openQA/languages","stargazers_url":"https://api.github.com/repos/asdil12/openQA/stargazers","contributors_url":"https://api.github.com/repos/asdil12/openQA/contributors","subscribers_url":"https://api.github.com/repos/asdil12/openQA/subscribers","subscription_url":"https://api.github.com/repos/asdil12/openQA/subscription","commits_url":"https://api.github.com/repos/asdil12/openQA/commits{/sha}","git_commits_url":"https://api.github.com/repos/asdil12/openQA/git/commits{/sha}","comments_url":"https://api.github.com/repos/asdil12/openQA/comments{/number}","issue_comment_url":"https://api.github.com/repos/asdil12/openQA/issues/comments{/number}","contents_url":"https://api.github.com/repos/asdil12/openQA/contents/{+path}","compare_url":"https://api.github.com/repos/asdil12/openQA/compare/{base}...{head}","merges_url":"https://api.github.com/repos/asdil12/openQA/merges","archive_url":"https://api.github.com/repos/asdil12/openQA/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/asdil12/openQA/downloads","issues_url":"https://api.github.com/repos/asdil12/openQA/issues{/number}","pulls_url":"https://api.github.com/repos/asdil12/openQA/pulls{/number}","milestones_url":"https://api.github.com/repos/asdil12/openQA/milestones{/number}","notifications_url":"https://api.github.com/repos/asdil12/openQA/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/asdil12/openQA/labels{/name}","releases_url":"https://api.github.com/repos/asdil12/openQA/releases{/id}","deployments_url":"https://api.github.com/repos/asdil12/openQA/deployments","created_at":"2015-04-20T15:12:26Z","updated_at":"2015-04-20T15:12:29Z","pushed_at":"2016-11-23T14:30:56Z","git_url":"git://github.com/asdil12/openQA.git","ssh_url":"git@github.com:asdil12/openQA.git","clone_url":"https://github.com/asdil12/openQA.git","svn_url":"https://github.com/asdil12/openQA","homepage":"http://openqa.opensuse.org/","size":15980,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"os-autoinst:master","ref":"master","sha":"02ff3adbb53b7a8631655e51369cb917193f8e93","user":{"login":"os-autoinst","id":6918706,"avatar_url":"https://avatars.githubusercontent.com/u/6918706?v=3","gravatar_id":"","url":"https://api.github.com/users/os-autoinst","html_url":"https://github.com/os-autoinst","followers_url":"https://api.github.com/users/os-autoinst/followers","following_url":"https://api.github.com/users/os-autoinst/following{/other_user}","gists_url":"https://api.github.com/users/os-autoinst/gists{/gist_id}","starred_url":"https://api.github.com/users/os-autoinst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/os-autoinst/subscriptions","organizations_url":"https://api.github.com/users/os-autoinst/orgs","repos_url":"https://api.github.com/users/os-autoinst/repos","events_url":"https://api.github.com/users/os-autoinst/events{/privacy}","received_events_url":"https://api.github.com/users/os-autoinst/received_events","type":"Organization","site_admin":false},"repo":{"id":20883829,"name":"openQA","full_name":"os-autoinst/openQA","owner":{"login":"os-autoinst","id":6918706,"avatar_url":"https://avatars.githubusercontent.com/u/6918706?v=3","gravatar_id":"","url":"https://api.github.com/users/os-autoinst","html_url":"https://github.com/os-autoinst","followers_url":"https://api.github.com/users/os-autoinst/followers","following_url":"https://api.github.com/users/os-autoinst/following{/other_user}","gists_url":"https://api.github.com/users/os-autoinst/gists{/gist_id}","starred_url":"https://api.github.com/users/os-autoinst/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/os-autoinst/subscriptions","organizations_url":"https://api.github.com/users/os-autoinst/orgs","repos_url":"https://api.github.com/users/os-autoinst/repos","events_url":"https://api.github.com/users/os-autoinst/events{/privacy}","received_events_url":"https://api.github.com/users/os-autoinst/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/os-autoinst/openQA","description":"openQA web-frontend, scheduler and tools","fork":false,"url":"https://api.github.com/repos/os-autoinst/openQA","forks_url":"https://api.github.com/repos/os-autoinst/openQA/forks","keys_url":"https://api.github.com/repos/os-autoinst/openQA/keys{/key_id}","collaborators_url":"https://api.github.com/repos/os-autoinst/openQA/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/os-autoinst/openQA/teams","hooks_url":"https://api.github.com/repos/os-autoinst/openQA/hooks","issue_events_url":"https://api.github.com/repos/os-autoinst/openQA/issues/events{/number}","events_url":"https://api.github.com/repos/os-autoinst/openQA/events","assignees_url":"https://api.github.com/repos/os-autoinst/openQA/assignees{/user}","branches_url":"https://api.github.com/repos/os-autoinst/openQA/branches{/branch}","tags_url":"https://api.github.com/repos/os-autoinst/openQA/tags","blobs_url":"https://api.github.com/repos/os-autoinst/openQA/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/os-autoinst/openQA/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/os-autoinst/openQA/git/refs{/sha}","trees_url":"https://api.github.com/repos/os-autoinst/openQA/git/trees{/sha}","statuses_url":"https://api.github.com/repos/os-autoinst/openQA/statuses/{sha}","languages_url":"https://api.github.com/repos/os-autoinst/openQA/languages","stargazers_url":"https://api.github.com/repos/os-autoinst/openQA/stargazers","contributors_url":"https://api.github.com/repos/os-autoinst/openQA/contributors","subscribers_url":"https://api.github.com/repos/os-autoinst/openQA/subscribers","subscription_url":"https://api.github.com/repos/os-autoinst/openQA/subscription","commits_url":"https://api.github.com/repos/os-autoinst/openQA/commits{/sha}","git_commits_url":"https://api.github.com/repos/os-autoinst/openQA/git/commits{/sha}","comments_url":"https://api.github.com/repos/os-autoinst/openQA/comments{/number}","issue_comment_url":"https://api.github.com/repos/os-autoinst/openQA/issues/comments{/number}","contents_url":"https://api.github.com/repos/os-autoinst/openQA/contents/{+path}","compare_url":"https://api.github.com/repos/os-autoinst/openQA/compare/{base}...{head}","merges_url":"https://api.github.com/repos/os-autoinst/openQA/merges","archive_url":"https://api.github.com/repos/os-autoinst/openQA/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/os-autoinst/openQA/downloads","issues_url":"https://api.github.com/repos/os-autoinst/openQA/issues{/number}","pulls_url":"https://api.github.com/repos/os-autoinst/openQA/pulls{/number}","milestones_url":"https://api.github.com/repos/os-autoinst/openQA/milestones{/number}","notifications_url":"https://api.github.com/repos/os-autoinst/openQA/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/os-autoinst/openQA/labels{/name}","releases_url":"https://api.github.com/repos/os-autoinst/openQA/releases{/id}","deployments_url":"https://api.github.com/repos/os-autoinst/openQA/deployments","created_at":"2014-06-16T12:23:22Z","updated_at":"2016-11-21T15:58:06Z","pushed_at":"2016-11-24T10:09:02Z","git_url":"git://github.com/os-autoinst/openQA.git","ssh_url":"git@github.com:os-autoinst/openQA.git","clone_url":"https://github.com/os-autoinst/openQA.git","svn_url":"https://github.com/os-autoinst/openQA","homepage":"http://openqa.opensuse.org/","size":17379,"stargazers_count":72,"watchers_count":72,"language":"Perl","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":58,"mirror_url":null,"open_issues_count":24,"forks":58,"open_issues":24,"watchers":72,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032"},"html":{"href":"https://github.com/os-autoinst/openQA/pull/1032"},"issue":{"href":"https://api.github.com/repos/os-autoinst/openQA/issues/1032"},"comments":{"href":"https://api.github.com/repos/os-autoinst/openQA/issues/1032/comments"},"review_comments":{"href":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032/comments"},"review_comment":{"href":"https://api.github.com/repos/os-autoinst/openQA/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/os-autoinst/openQA/pulls/1032/commits"},"statuses":{"href":"https://api.github.com/repos/os-autoinst/openQA/statuses/917bf81bb11f25eac1d9588d4124114ec87c51a4"}}}}
{"actor":{"display_login":"coolo"}}