kuroko2 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/kuroko2/definition_linker.js +1 -1
- data/app/assets/stylesheets/kuroko2/application.scss +4 -0
- data/app/controllers/kuroko2/api/job_instances_controller.rb +3 -2
- data/app/controllers/kuroko2/dashboard_controller.rb +1 -1
- data/app/controllers/kuroko2/job_definitions_controller.rb +2 -2
- data/app/controllers/kuroko2/job_instances_controller.rb +8 -18
- data/app/controllers/kuroko2/tokens_controller.rb +3 -3
- data/app/controllers/kuroko2/users_controller.rb +17 -1
- data/app/models/kuroko2/job_definition.rb +11 -0
- data/app/models/kuroko2/job_instance.rb +19 -2
- data/app/models/kuroko2/job_schedule.rb +3 -6
- data/app/models/kuroko2/job_suspend_schedule.rb +1 -1
- data/app/models/kuroko2/token.rb +8 -0
- data/app/views/kuroko2/execution_logs/index.json.jbuilder +1 -1
- data/app/views/kuroko2/job_definitions/_form.html.slim +6 -1
- data/app/views/kuroko2/job_definitions/_list.html.slim +12 -5
- data/app/views/kuroko2/job_definitions/_search_results.html.slim +10 -3
- data/app/views/kuroko2/job_definitions/show.html.slim +5 -3
- data/app/views/kuroko2/job_timelines/dataset.json.jbuilder +1 -1
- data/app/views/kuroko2/logs/index.html.slim +6 -6
- data/app/views/kuroko2/tokens/index.html.slim +2 -2
- data/app/views/kuroko2/users/edit.html.slim +37 -0
- data/app/views/kuroko2/users/show.html.slim +8 -4
- data/db/migrate/026_add_webhook_url_to_job_definitions.rb +5 -0
- data/lib/autoload/kuroko2/workflow/engine.rb +4 -6
- data/lib/autoload/kuroko2/workflow/notifier/concerns/chat_message_builder.rb +12 -0
- data/lib/autoload/kuroko2/workflow/notifier/hipchat.rb +30 -4
- data/lib/autoload/kuroko2/workflow/notifier/mail.rb +9 -1
- data/lib/autoload/kuroko2/workflow/notifier/slack.rb +31 -4
- data/lib/autoload/kuroko2/workflow/notifier/webhook.rb +173 -0
- data/lib/autoload/kuroko2/workflow/task/queue.rb +2 -2
- data/lib/autoload/kuroko2/workflow/task/sub_process.rb +2 -4
- data/lib/kuroko2/version.rb +1 -1
- data/spec/controllers/users_controller_spec.rb +51 -2
- data/spec/dummy/config/kuroko2.yml +2 -0
- data/spec/dummy/db/schema.rb +76 -92
- data/spec/dummy/log/development.log +1143 -0
- data/spec/dummy/log/test.log +271238 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-Q/-QhKaYdB1JJGAsq6Ih7uQZJD46XkY5Gw0-38DBDVg3Y.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-h/-h4P8jVHGGfJVwG36J8kBUkHFa3HHGNiJQz0936uaxg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/24/24laeo7m53bkbst3Gxu4hlJY-EbnK-rQxH-DA4ujzwY.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2e/2eEFzw4UUZHJizptl3nT5jVv3IL25_RdYImr3lAVlJ4.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2z/2z8OmZrK1FFsPb8zq9RFli2IVM0gOna92hieZ4cK36c.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4K/4Ky9Fg4qo8d_i8bJF6NOhDpxHuJ5kIX8n0w6C8wdHDU.cache +3 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Di/Di9ZEIp2OLO96tkqFN21AWfdoAhc0OCBOJb3o8RUk1I.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ex/ExgjnrLZM8Hc_uT_sWVaQSNR26tGYCGUsbJDXs9GYO0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/FJ/FJW4oZDLKhsjg_UHdycQAY88BFtnMeeLCuArx6HIMdM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Iq/IqSpSELRWrOQtOK8F6mGZFPvfafM4yn8gB_VquH9E50.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/JJ/JJ2dvNSAjiGkZZs_1Dz2TMWDJs4HypQ95b26cHN13I0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LJ/LJsVKu6GCC14s20BfJEDXwajK6-xWF72ANX5ONOTX1w.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/LL/LLCxb9El_km568UsA8DDOe8Vh3pPKE8IU6ZNww9ie8s.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Pq/pqeS6zqHUdv-_25W2PSQMm31ql_cIpaK1iqEcfiNyUQ.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Q9/Q9TwXzoqqs8Dm9v25gjZxYIkZW1UKm2X8g2koo5aYhQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QJ/QJNiKbGgll2T_0mhQus6ZL9a2SM4Xqz7vs2V2KbELPw.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/QV/QVVeFw88kC-7HfzOk_dCVoFBnz9W_7-gmJFYh-Xlh-0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Qs/QsTn160WUaI8_u8tE8rz37XiSV9qLvSxiXAR-tCtV3Y.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/V2/V2QhbjrEGa7in5Uj1P-3E1Ziw2AGno_ADefUhPNHw_A.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Vj/VjICw6h8uQ_278ekFlu1znnPR8Gz1vWF_mRgy0KjZXs.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/dH/dHFrKzzqtF3aoKs2wAI8z0CNHZoNuytfiHur9Zgz9z0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fE/fEFAQG1Uqt2e58VitSFoPsjVjntfPtgL9RKoKHUTS9U.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fM/FMdA_jabowoG5SAWE93G7Hu8A-5GhfzC9Gjy3EJp1Ts.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hI/hIIciXZzgFWXdW0lamhs4r5zFFr4hnXvWAuOihCS5qI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hW/hWOkA9ZbQJy1YfEXThjYPOiXRDVRgAeW8TmLm-uQCYk.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/iv/ivrIChCv2olhH20VXJQTJgVWlx3t9ncsYxV0QfLT0Bs.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/k3/k31T18tx4gR2rhpmDMYMLUa8KPDt7QRIR_qRK56LOdE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oB/oB0c7AuqQVdgqJDgphXXOHw3SXqbDUYfZWxxm9-v_is.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ou/ouMQatdL-PPhPVPw5o0xm5EBkVeVWLti06EUEVmfOBo.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/qM/qMZbagtANt1BI7qOJXWEpzxx1qa-IKMkyOy6EKEIIbE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/rc/rcceqGk009vh5_tK6Y-i1dvbYQwuUtRF888xZcnZrj8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sJ/sJOLo6McRe1YhfgIaGhcDaAoulIdYY7Rs07TAKmrSoY.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sh/shGRyWpXjqxMTGB3As4Vibs8VGS0bZHHd4s0qabhwXI.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sr/SRfo3vCtDVy0qd-OB9dv5a-xIVTHkJZDn8XwY_ymy7g.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/vV/vV3Loym0NolgPoXFEVPOr5rDgB_Q5kvUA3InuEEvEvQ.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wK/wK5S37PPHfwFm-4mrLMMPdOZ29-H75zo1T2gmErWjLI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wm/wm_qI7_LCxbnH6p7BK1Pqcocl-6TcULzTERICGZIdL0.cache +1 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zC/zCYIl3BglB_fMHME2oqK30CF97CBUG09R0ICLpE-pIM.cache +0 -0
- data/spec/features/dashborad_spec.rb +10 -3
- data/spec/features/users_spec.rb +20 -4
- data/spec/models/job_instance_spec.rb +1 -1
- data/spec/models/token_spec.rb +38 -0
- data/spec/workflow/notifier/hipchat_spec.rb +91 -0
- data/spec/workflow/notifier/mail_spec.rb +18 -2
- data/spec/workflow/notifier/slack_spec.rb +85 -0
- data/spec/workflow/notifier/webhook_spec.rb +187 -0
- data/spec/workflow/task/queue_spec.rb +11 -0
- metadata +93 -16
@@ -12,13 +12,13 @@ ul class="nav nav-pills" role="tablist"
|
|
12
12
|
table.table.table-condensed.table-hover data-reload="#{@instance.working? && !@instance.error?}"
|
13
13
|
thead
|
14
14
|
tr
|
15
|
-
th
|
15
|
+
th
|
16
16
|
th.col-md-1 Time
|
17
17
|
th.col-md-10 Message
|
18
18
|
- for log in @logs
|
19
19
|
tr
|
20
20
|
td= labeled_log_level(log.level)
|
21
|
-
td.nowrap=
|
21
|
+
td.nowrap= log.created_at
|
22
22
|
td.log= rinku_auto_link(log.message, :urls)
|
23
23
|
= javascript_include_tag 'kuroko2/instance_linker'
|
24
24
|
|
@@ -26,8 +26,8 @@ ul class="nav nav-pills" role="tablist"
|
|
26
26
|
table.table.table-condensed.table-hover
|
27
27
|
thead
|
28
28
|
tr
|
29
|
-
th
|
30
|
-
th
|
31
|
-
th
|
32
|
-
th.col-md-
|
29
|
+
th Time
|
30
|
+
th PID
|
31
|
+
th Token
|
32
|
+
th.col-md-7 Message
|
33
33
|
tbody#execution_log_body
|
@@ -21,14 +21,14 @@
|
|
21
21
|
params: { invoke: 'retry' },
|
22
22
|
class: 'btn btn-default btn-block btn-xs',
|
23
23
|
role: 'button',
|
24
|
-
disabled: !token.
|
24
|
+
disabled: !token.retryable?)
|
25
25
|
td.col-md-3= button_to('Skip',
|
26
26
|
job_definition_job_instance_token_path(job_definition_id: @definition.id, job_instance_id: @instance.id, id: token.id),
|
27
27
|
method: :patch,
|
28
28
|
params: { invoke: 'skip' },
|
29
29
|
class: 'btn btn-default btn-block btn-xs',
|
30
30
|
role: 'button',
|
31
|
-
disabled: !token.
|
31
|
+
disabled: !token.skippable?,
|
32
32
|
data: { confirm: 'Continue executing job script? If not, use "Cancel" button.' })
|
33
33
|
- if (execution = token.execution)
|
34
34
|
tr
|
@@ -0,0 +1,37 @@
|
|
1
|
+
- @title = "#{@user.name_was} « Users"
|
2
|
+
- @content_title = "Edit User"
|
3
|
+
|
4
|
+
- content_for :breadcrumb do
|
5
|
+
ol.breadcrumb
|
6
|
+
li= link_to raw('<i class="fa fa-users"></i> Users'), users_path
|
7
|
+
li= link_to 'Details', user_path(@user)
|
8
|
+
li.active Edit User
|
9
|
+
|
10
|
+
.row
|
11
|
+
.col-md-12
|
12
|
+
.box
|
13
|
+
= form_for @user, method: :put do |form|
|
14
|
+
.box-header
|
15
|
+
h2.box-title ##{@user.id} #{@user.name_was}
|
16
|
+
.box-body.table-responsive
|
17
|
+
- if @user.errors.present?
|
18
|
+
.row
|
19
|
+
ul.alert.alert-danger
|
20
|
+
- @user.errors.full_messages.each do |message|
|
21
|
+
li #{message}
|
22
|
+
|
23
|
+
.row
|
24
|
+
.col-md-2.visible-lg-block.visible-md-block
|
25
|
+
img.img-circle src='#{@user.image}' alt="#{@user.name_was}"
|
26
|
+
.col-md-10
|
27
|
+
div class="form-group #{@user.errors.has_key?(:name) ? 'has-error' : ''}"
|
28
|
+
= form.label :name
|
29
|
+
= form.text_field :name, class: 'form-control', placeholder: 'Group Name'
|
30
|
+
div class="form-group #{@user.errors.has_key?(:email) ? 'has-error' : ''}"
|
31
|
+
= form.label :email
|
32
|
+
= form.text_field :email, class: 'form-control', placeholder: 'group@example.com'
|
33
|
+
.box-footer
|
34
|
+
.row
|
35
|
+
.col-md-3.col-md-offset-9
|
36
|
+
.form-group
|
37
|
+
= form.submit 'Update', class: 'btn btn-default btn-block'
|
@@ -26,10 +26,14 @@
|
|
26
26
|
- unless @user.google_account?
|
27
27
|
th Note
|
28
28
|
td This account is group account.
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
|
30
|
+
- unless @user.google_account?
|
31
|
+
.box-footer
|
32
|
+
.row
|
33
|
+
.col-md-3.col-md-offset-6
|
34
|
+
= link_to 'Edit User', edit_user_path(@user), class: 'btn btn-default btn-block', role: 'button'
|
35
|
+
.col-md-3
|
36
|
+
= link_to 'Destroy User', @user, method: :delete, class: 'btn btn-default btn-block', role: 'button', data: { confirm: 'Are you sure?' }
|
33
37
|
.col-md-7
|
34
38
|
.box#definitions
|
35
39
|
.box-header
|
@@ -30,7 +30,7 @@ module Kuroko2
|
|
30
30
|
|
31
31
|
Kuroko2.logger.info(message)
|
32
32
|
|
33
|
-
Notifier.notify(:
|
33
|
+
Notifier.notify(:retrying, token.job_instance)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -49,7 +49,7 @@ module Kuroko2
|
|
49
49
|
|
50
50
|
Kuroko2.logger.info(message)
|
51
51
|
|
52
|
-
Notifier.notify(:
|
52
|
+
Notifier.notify(:skipping, token.job_instance)
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -100,15 +100,13 @@ module Kuroko2
|
|
100
100
|
message = "(token #{token.uuid}) Marked as 'finished'."
|
101
101
|
|
102
102
|
token.job_instance.logs.info(message)
|
103
|
+
Kuroko2.logger.info(message)
|
103
104
|
token.mark_as_finished
|
104
105
|
unless token.parent
|
105
106
|
token.job_instance.touch(:finished_at)
|
107
|
+
Notifier.notify(:finished, token.job_instance)
|
106
108
|
token.destroy!
|
107
109
|
end
|
108
|
-
|
109
|
-
Kuroko2.logger.info(message)
|
110
|
-
|
111
|
-
Notifier.notify(:finished, token.job_instance)
|
112
110
|
end
|
113
111
|
end
|
114
112
|
|
@@ -16,6 +16,18 @@ module Kuroko2
|
|
16
16
|
"Finished to execute '#{@definition.name}'"
|
17
17
|
end
|
18
18
|
|
19
|
+
def launched_text
|
20
|
+
"Launched '#{@definition.name}'"
|
21
|
+
end
|
22
|
+
|
23
|
+
def retrying_text
|
24
|
+
"Retrying the current task in '#{@definition.name}'"
|
25
|
+
end
|
26
|
+
|
27
|
+
def skipping_text
|
28
|
+
"Skipping the current task in '#{@definition.name}'"
|
29
|
+
end
|
30
|
+
|
19
31
|
def long_elapsed_time_text
|
20
32
|
"The running time is longer than expected '#{@definition.name}'."
|
21
33
|
end
|
@@ -13,15 +13,41 @@ module Kuroko2
|
|
13
13
|
@message_builder = Workflow::Notifier::Concerns::ChatMessageBuilder.new(instance)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def notify_launch
|
17
|
+
if @definition.hipchat_notify_finished?
|
18
|
+
message = build_message(level: 'SUCCESS', text: message_builder.launched_text)
|
19
|
+
message << "<br>"
|
20
|
+
message << @instance.logs.reverse.detect{ |log| log.level == 'INFO' }.try!(:message)
|
21
|
+
|
22
|
+
send_to_hipchat(message, color: 'yellow')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def notify_retrying
|
27
|
+
if @definition.hipchat_notify_finished
|
28
|
+
message = build_message(level: 'SUCCESS', text: message_builder.retrying_text)
|
29
|
+
message << "<br>"
|
30
|
+
message << @instance.logs.last(2).first.message
|
31
|
+
|
32
|
+
send_to_hipchat(message, color: 'yellow')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def notify_skipping
|
37
|
+
if @definition.hipchat_notify_finished
|
38
|
+
message = build_message(level: 'SUCCESS', text: message_builder.skipping_text)
|
39
|
+
message << "<br>"
|
40
|
+
message << @instance.logs.last(2).first.message
|
41
|
+
|
42
|
+
send_to_hipchat(message, color: 'yellow')
|
43
|
+
end
|
18
44
|
end
|
19
45
|
|
20
46
|
def notify_cancellation
|
21
|
-
if @definition.notify_cancellation
|
47
|
+
if @definition.notify_cancellation || @definition.hipchat_notify_finished?
|
22
48
|
message = build_message(level: 'WARNING', text: message_builder.failure_text)
|
23
49
|
message << "<br>"
|
24
|
-
message << @instance.logs.
|
50
|
+
message << @instance.logs.reverse.detect{ |log| log.level == 'WARN' }.try!(:message)
|
25
51
|
|
26
52
|
send_to_hipchat(message, color: 'yellow')
|
27
53
|
end
|
@@ -9,6 +9,7 @@ module Kuroko2
|
|
9
9
|
FAILURE = 'danger'
|
10
10
|
CRITICAL = 'danger'
|
11
11
|
SUCCESS = 'good'
|
12
|
+
INFO = '#439FE0'
|
12
13
|
end
|
13
14
|
|
14
15
|
def initialize(instance)
|
@@ -18,16 +19,42 @@ module Kuroko2
|
|
18
19
|
@webhook_url = Kuroko2.config.notifiers.slack.webhook_url
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
-
|
22
|
+
def notify_launch
|
23
|
+
if @definition.hipchat_notify_finished?
|
24
|
+
send_attachment_message_to_slack(
|
25
|
+
level: 'INFO',
|
26
|
+
text: message_builder.launched_text,
|
27
|
+
body: @instance.logs.reverse.detect{ |log| log.level == 'INFO' }.try!(:message),
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def notify_retrying
|
33
|
+
if @definition.hipchat_notify_finished?
|
34
|
+
send_attachment_message_to_slack(
|
35
|
+
level: 'INFO',
|
36
|
+
text: message_builder.retrying_text,
|
37
|
+
body: @instance.logs.last(2).first.message,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def notify_skipping
|
43
|
+
if @definition.hipchat_notify_finished?
|
44
|
+
send_attachment_message_to_slack(
|
45
|
+
level: 'INFO',
|
46
|
+
text: message_builder.skipping_text,
|
47
|
+
body: @instance.logs.last(2).first.message,
|
48
|
+
)
|
49
|
+
end
|
23
50
|
end
|
24
51
|
|
25
52
|
def notify_cancellation
|
26
|
-
if @definition.notify_cancellation
|
53
|
+
if @definition.notify_cancellation || @definition.hipchat_notify_finished?
|
27
54
|
send_attachment_message_to_slack(
|
28
55
|
level: 'WARNING',
|
29
56
|
text: message_builder.failure_text,
|
30
|
-
body: @instance.logs.
|
57
|
+
body: @instance.logs.reverse.detect{ |log| log.level == 'WARN' }.try!(:message),
|
31
58
|
)
|
32
59
|
end
|
33
60
|
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Kuroko2
|
2
|
+
module Workflow
|
3
|
+
module Notifier
|
4
|
+
class Webhook
|
5
|
+
attr_reader :message_builder
|
6
|
+
|
7
|
+
HASH_ALGORITHM = 'sha256'
|
8
|
+
HMAC_DIGEST = OpenSSL::Digest.new(HASH_ALGORITHM)
|
9
|
+
|
10
|
+
def initialize(instance)
|
11
|
+
@instance = instance
|
12
|
+
@definition = instance.job_definition
|
13
|
+
@message_builder = Workflow::Notifier::Concerns::ChatMessageBuilder.new(instance)
|
14
|
+
@secret_token = Kuroko2.config.notifiers.webhook.try!(:secret_token)
|
15
|
+
end
|
16
|
+
|
17
|
+
def notify_launch
|
18
|
+
if @definition.hipchat_notify_finished?
|
19
|
+
request(
|
20
|
+
build_payload(
|
21
|
+
action: 'notify_launch',
|
22
|
+
level: 'INFO',
|
23
|
+
subject: message_builder.launched_text,
|
24
|
+
message: @instance.logs.reverse.detect{ |log| log.level == 'INFO' }.try!(:message),
|
25
|
+
)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def notify_retrying
|
31
|
+
if @definition.hipchat_notify_finished?
|
32
|
+
request(
|
33
|
+
build_payload(
|
34
|
+
action: 'notify_retrying',
|
35
|
+
level: 'INFO',
|
36
|
+
subject: message_builder.retrying_text,
|
37
|
+
message: @instance.logs.last(2).first.message,
|
38
|
+
)
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def notify_skipping
|
44
|
+
if @definition.hipchat_notify_finished?
|
45
|
+
request(
|
46
|
+
build_payload(
|
47
|
+
action: 'notify_skipping',
|
48
|
+
level: 'INFO',
|
49
|
+
subject: message_builder.skipping_text,
|
50
|
+
message: @instance.logs.last(2).first.message,
|
51
|
+
)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def notify_cancellation
|
57
|
+
if @definition.notify_cancellation || @definition.hipchat_notify_finished?
|
58
|
+
request(
|
59
|
+
build_payload(
|
60
|
+
action: 'notify_cancellation',
|
61
|
+
level: 'WARNING',
|
62
|
+
subject: message_builder.failure_text,
|
63
|
+
message: @instance.logs.reverse.detect{ |log| log.level == 'WARN' }.try!(:message),
|
64
|
+
)
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def notify_failure
|
70
|
+
request(
|
71
|
+
build_payload(
|
72
|
+
action: 'notify_failure',
|
73
|
+
level: 'FAILURE',
|
74
|
+
subject: message_builder.failure_text,
|
75
|
+
message: @instance.logs.last(2).first.message,
|
76
|
+
)
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def notify_critical
|
81
|
+
request(
|
82
|
+
build_payload(
|
83
|
+
action: 'notify_critical',
|
84
|
+
level: 'CRITICAL',
|
85
|
+
subject: message_builder.failure_text,
|
86
|
+
message: @instance.logs.last(2).first.message,
|
87
|
+
)
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def notify_finished
|
92
|
+
if @definition.hipchat_notify_finished?
|
93
|
+
request(
|
94
|
+
build_payload(
|
95
|
+
action: 'notify_finished',
|
96
|
+
level: 'SUCCESS',
|
97
|
+
subject: message_builder.finished_text,
|
98
|
+
)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def notify_long_elapsed_time
|
104
|
+
request(
|
105
|
+
build_payload(
|
106
|
+
action: 'notify_long_elapsed_time',
|
107
|
+
level: 'WARNING',
|
108
|
+
subject: message_builder.long_elapsed_time_text,
|
109
|
+
)
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def request(body)
|
116
|
+
return unless @definition.webhook_url.present?
|
117
|
+
|
118
|
+
url = URI.parse(@definition.webhook_url)
|
119
|
+
conn = Faraday.new(url: "#{url.scheme}://#{url.host}") do |faraday|
|
120
|
+
faraday.port = url.port
|
121
|
+
faraday.adapter Faraday.default_adapter
|
122
|
+
end
|
123
|
+
|
124
|
+
json = body.to_json
|
125
|
+
response = conn.post do |req|
|
126
|
+
req.url(url.path)
|
127
|
+
|
128
|
+
req.headers['X-Kuroko2-Id'] = SecureRandom.uuid
|
129
|
+
if @secret_token.present?
|
130
|
+
req.headers['X-Kuroko2-Signature'] = "#{HASH_ALGORITHM}=#{OpenSSL::HMAC.hexdigest(HMAC_DIGEST, @secret_token, json)}"
|
131
|
+
end
|
132
|
+
|
133
|
+
req.headers['User-Agent'] = 'Kuroko2-Webhook'
|
134
|
+
req.headers['Content-Type'] = 'application/json'
|
135
|
+
req.body = json
|
136
|
+
end
|
137
|
+
|
138
|
+
unless response.success?
|
139
|
+
Kuroko2.logger.fatal("Failure sending webhook: status=#{response.status} body=#{response.body}")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def build_payload(action:, level:, subject:, message: nil)
|
144
|
+
{
|
145
|
+
action: action,
|
146
|
+
level: level,
|
147
|
+
subject: subject,
|
148
|
+
message: message,
|
149
|
+
job_instance: {
|
150
|
+
url: message_builder.job_instance_path,
|
151
|
+
id: @instance.id,
|
152
|
+
script: @instance.script,
|
153
|
+
finished_at: @instance.finished_at.try!(:iso8601),
|
154
|
+
canceled_at: @instance.canceled_at.try!(:iso8601),
|
155
|
+
error_at: @instance.error_at.try!(:iso8601),
|
156
|
+
created_at: @instance.created_at.try!(:iso8601),
|
157
|
+
},
|
158
|
+
job_definition: {
|
159
|
+
url: Kuroko2::Engine.routes.url_helpers.job_definition_url(
|
160
|
+
@definition,
|
161
|
+
host: Kuroko2.config.url_host,
|
162
|
+
protocol: Kuroko2.config.url_scheme,
|
163
|
+
),
|
164
|
+
id: @definition.id,
|
165
|
+
name: @definition.name,
|
166
|
+
description: @definition.description,
|
167
|
+
}
|
168
|
+
}
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|