Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a80a29d6
Commit
a80a29d6
authored
Jun 06, 2020
by
Sean Arnold
Committed by
Peter Leitzen
Jun 06, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add alert_event to services model
- Setup helpers and other translations - Move human name to helper
parent
b146cfda
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
324 additions
and
7 deletions
+324
-7
app/models/alert_management/alert.rb
app/models/alert_management/alert.rb
+11
-0
app/models/project_services/chat_message/alert_message.rb
app/models/project_services/chat_message/alert_message.rb
+74
-0
app/models/project_services/slack_service.rb
app/models/project_services/slack_service.rb
+15
-1
app/models/service.rb
app/models/service.rb
+5
-1
app/services/alert_management/process_prometheus_alert_service.rb
...ices/alert_management/process_prometheus_alert_service.rb
+4
-1
app/services/projects/alerting/notify_service.rb
app/services/projects/alerting/notify_service.rb
+12
-3
changelogs/unreleased/216326-send-alerts-to-slack-db-settings.yml
...gs/unreleased/216326-send-alerts-to-slack-db-settings.yml
+5
-0
db/migrate/20200526013844_add_alert_events_to_services.rb
db/migrate/20200526013844_add_alert_events_to_services.rb
+19
-0
db/structure.sql
db/structure.sql
+3
-1
lib/gitlab/data_builder/alert.rb
lib/gitlab/data_builder/alert.rb
+27
-0
spec/lib/gitlab/data_builder/alert_spec.rb
spec/lib/gitlab/data_builder/alert_spec.rb
+26
-0
spec/lib/gitlab/import_export/safe_model_attributes.yml
spec/lib/gitlab/import_export/safe_model_attributes.yml
+1
-0
spec/models/project_services/chat_message/alert_message_spec.rb
...odels/project_services/chat_message/alert_message_spec.rb
+48
-0
spec/models/service_spec.rb
spec/models/service_spec.rb
+14
-0
spec/services/alert_management/process_prometheus_alert_service_spec.rb
...alert_management/process_prometheus_alert_service_spec.rb
+30
-0
spec/services/projects/alerting/notify_service_spec.rb
spec/services/projects/alerting/notify_service_spec.rb
+30
-0
No files found.
app/models/alert_management/alert.rb
View file @
a80a29d6
...
...
@@ -150,8 +150,19 @@ module AlertManagement
''
end
def
execute_services
return
unless
Feature
.
enabled?
(
:alert_slack_event
,
project
)
return
unless
project
.
has_active_services?
(
:alert_hooks
)
project
.
execute_services
(
hook_data
,
:alert_hooks
)
end
private
def
hook_data
Gitlab
::
DataBuilder
::
Alert
.
build
(
self
)
end
def
hosts_length
return
unless
hosts
...
...
app/models/project_services/chat_message/alert_message.rb
0 → 100644
View file @
a80a29d6
# frozen_string_literal: true
module
ChatMessage
class
AlertMessage
<
BaseMessage
attr_reader
:title
attr_reader
:alert_url
attr_reader
:severity
attr_reader
:events
attr_reader
:status
attr_reader
:started_at
def
initialize
(
params
)
@project_name
=
params
[
:project_name
]
||
params
.
dig
(
:project
,
:path_with_namespace
)
@project_url
=
params
.
dig
(
:project
,
:web_url
)
||
params
[
:project_url
]
@title
=
params
.
dig
(
:object_attributes
,
:title
)
@alert_url
=
params
.
dig
(
:object_attributes
,
:url
)
@severity
=
params
.
dig
(
:object_attributes
,
:severity
)
@events
=
params
.
dig
(
:object_attributes
,
:events
)
@status
=
params
.
dig
(
:object_attributes
,
:status
)
@started_at
=
params
.
dig
(
:object_attributes
,
:started_at
)
end
def
attachments
[{
title:
title
,
title_link:
alert_url
,
color:
attachment_color
,
fields:
attachment_fields
}]
end
def
message
"Alert firing in
#{
project_name
}
"
end
private
def
attachment_color
"#C95823"
end
def
attachment_fields
[
{
title:
"Severity"
,
value:
severity
.
to_s
.
humanize
,
short:
true
},
{
title:
"Events"
,
value:
events
,
short:
true
},
{
title:
"Status"
,
value:
status
.
to_s
.
humanize
,
short:
true
},
{
title:
"Start time"
,
value:
format_time
(
started_at
),
short:
true
}
]
end
# This formats time into the following format
# April 23rd, 2020 1:06AM UTC
def
format_time
(
time
)
time
=
Time
.
zone
.
parse
(
time
.
to_s
)
time
.
strftime
(
"%B
#{
time
.
day
.
ordinalize
}
, %Y%l:%M%p %Z"
)
end
end
end
app/models/project_services/slack_service.rb
View file @
a80a29d6
# frozen_string_literal: true
class
SlackService
<
ChatNotificationService
prop_accessor
EVENT_CHANNEL
[
'alert'
]
def
title
'Slack notifications'
end
...
...
@@ -21,13 +23,25 @@ class SlackService < ChatNotificationService
'https://hooks.slack.com/services/…'
end
def
supported_events
additional
=
[]
additional
<<
'alert'
if
Feature
.
enabled?
(
:alert_slack_event
,
project
)
super
+
additional
end
def
get_message
(
object_kind
,
data
)
return
ChatMessage
::
AlertMessage
.
new
(
data
)
if
object_kind
==
'alert'
super
end
module
Notifier
private
def
notify
(
message
,
opts
)
# See https://gitlab.com/gitlab-org/slack-notifier/#custom-http-client
notifier
=
Slack
::
Messenger
.
new
(
webhook
,
opts
.
merge
(
http_client:
HTTPClient
))
notifier
.
ping
(
message
.
pretext
,
attachments:
message
.
attachments
,
...
...
app/models/service.rb
View file @
a80a29d6
...
...
@@ -22,6 +22,7 @@ class Service < ApplicationRecord
serialize
:properties
,
JSON
# rubocop:disable Cop/ActiveRecordSerialize
default_value_for
:active
,
false
default_value_for
:alert_events
,
true
default_value_for
:push_events
,
true
default_value_for
:issues_events
,
true
default_value_for
:confidential_issues_events
,
true
...
...
@@ -72,6 +73,7 @@ class Service < ApplicationRecord
scope
:pipeline_hooks
,
->
{
where
(
pipeline_events:
true
,
active:
true
)
}
scope
:wiki_page_hooks
,
->
{
where
(
wiki_page_events:
true
,
active:
true
)
}
scope
:deployment_hooks
,
->
{
where
(
deployment_events:
true
,
active:
true
)
}
scope
:alert_hooks
,
->
{
where
(
alert_events:
true
,
active:
true
)
}
scope
:external_issue_trackers
,
->
{
issue_trackers
.
active
.
without_defaults
}
scope
:deployment
,
->
{
where
(
category:
'deployment'
)
}
...
...
@@ -172,7 +174,7 @@ class Service < ApplicationRecord
end
def
configurable_events
events
=
s
elf
.
class
.
s
upported_events
events
=
supported_events
# No need to disable individual triggers when there is only one
if
events
.
count
==
1
...
...
@@ -403,6 +405,8 @@ class Service < ApplicationRecord
"Event will be triggered when a commit is created/updated"
when
"deployment"
"Event will be triggered when a deployment finishes"
when
"alert"
"Event will be triggered when a new, unique alert is recorded"
end
end
...
...
app/services/alert_management/process_prometheus_alert_service.rb
View file @
a80a29d6
...
...
@@ -48,7 +48,10 @@ module AlertManagement
def
create_alert_management_alert
am_alert
=
AlertManagement
::
Alert
.
new
(
am_alert_params
.
merge
(
ended_at:
nil
))
return
if
am_alert
.
save
if
am_alert
.
save
am_alert
.
execute_services
return
end
logger
.
warn
(
message:
'Unable to create AlertManagement::Alert'
,
...
...
app/services/projects/alerting/notify_service.rb
View file @
a80a29d6
...
...
@@ -32,15 +32,24 @@ module Projects
end
def
process_alert
if
alert
=
find_alert_by_fingerprint
(
am_alert_params
[
:fingerprint
])
alert
.
register_new_event!
existing_alert
=
find_alert_by_fingerprint
(
am_alert_params
[
:fingerprint
])
if
existing_alert
process_existing_alert
(
existing_alert
)
else
create_alert
end
end
def
process_existing_alert
(
alert
)
alert
.
register_new_event!
end
def
create_alert
AlertManagement
::
Alert
.
create
(
am_alert_params
)
alert
=
AlertManagement
::
Alert
.
create
(
am_alert_params
)
alert
.
execute_services
if
alert
.
persisted?
alert
end
def
find_alert_by_fingerprint
(
fingerprint
)
...
...
changelogs/unreleased/216326-send-alerts-to-slack-db-settings.yml
0 → 100644
View file @
a80a29d6
---
title
:
Add column for alert slack notifications
merge_request
:
33017
author
:
type
:
added
db/migrate/20200526013844_add_alert_events_to_services.rb
0 → 100644
View file @
a80a29d6
# frozen_string_literal: true
class
AddAlertEventsToServices
<
ActiveRecord
::
Migration
[
6.0
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
up
with_lock_retries
do
add_column
:services
,
:alert_events
,
:boolean
end
end
def
down
with_lock_retries
do
remove_column
:services
,
:alert_events
end
end
end
db/structure.sql
View file @
a80a29d6
...
...
@@ -6147,7 +6147,8 @@ CREATE TABLE public.services (
template
boolean
DEFAULT
false
,
instance
boolean
DEFAULT
false
NOT
NULL
,
comment_detail
smallint
,
inherit_from_id
bigint
inherit_from_id
bigint
,
alert_events
boolean
);
CREATE
SEQUENCE
public
.
services_id_seq
...
...
@@ -13778,6 +13779,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200525114553
20200525121014
20200526000407
20200526013844
20200526120714
20200526153844
20200526164946
...
...
lib/gitlab/data_builder/alert.rb
0 → 100644
View file @
a80a29d6
# frozen_string_literal: true
module
Gitlab
module
DataBuilder
module
Alert
extend
self
def
build
(
alert
)
{
object_kind:
'alert'
,
object_attributes:
hook_attrs
(
alert
)
}
end
def
hook_attrs
(
alert
)
{
title:
alert
.
title
,
url:
Gitlab
::
Routing
.
url_helpers
.
details_project_alert_management_url
(
alert
.
project
,
alert
.
iid
),
severity:
alert
.
severity
,
events:
alert
.
events
,
status:
alert
.
status_name
,
started_at:
alert
.
started_at
}
end
end
end
end
spec/lib/gitlab/data_builder/alert_spec.rb
0 → 100644
View file @
a80a29d6
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
DataBuilder
::
Alert
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:alert
)
{
create
(
:alert_management_alert
,
project:
project
)
}
describe
'.build'
do
let_it_be
(
:data
)
{
described_class
.
build
(
alert
)
}
it
{
expect
(
data
).
to
be_a
(
Hash
)
}
it
{
expect
(
data
[
:object_kind
]).
to
eq
(
'alert'
)
}
it
'contains the correct object attributes'
,
:aggregate_failures
do
object_attributes
=
data
[
:object_attributes
]
expect
(
object_attributes
[
:title
]).
to
eq
(
alert
.
title
)
expect
(
object_attributes
[
:url
]).
to
eq
(
Gitlab
::
Routing
.
url_helpers
.
details_project_alert_management_url
(
project
,
alert
.
iid
))
expect
(
object_attributes
[
:severity
]).
to
eq
(
alert
.
severity
)
expect
(
object_attributes
[
:events
]).
to
eq
(
alert
.
events
)
expect
(
object_attributes
[
:status
]).
to
eq
(
alert
.
status_name
)
expect
(
object_attributes
[
:started_at
]).
to
eq
(
alert
.
started_at
)
end
end
end
spec/lib/gitlab/import_export/safe_model_attributes.yml
View file @
a80a29d6
...
...
@@ -472,6 +472,7 @@ Service:
-
properties
-
template
-
instance
-
alert_events
-
push_events
-
issues_events
-
commit_events
...
...
spec/models/project_services/chat_message/alert_message_spec.rb
0 → 100644
View file @
a80a29d6
# frozen_string_literal: true
require
'spec_helper'
describe
ChatMessage
::
AlertMessage
do
subject
{
described_class
.
new
(
args
)
}
let
(
:alert
)
{
create
(
:alert_management_alert
)
}
let
(
:args
)
do
{
project_name:
'project_name'
,
project_url:
'http://example.com'
}.
merge
(
Gitlab
::
DataBuilder
::
Alert
.
build
(
alert
))
end
describe
'#message'
do
it
'returns the correct message'
do
expect
(
subject
.
message
).
to
eq
(
"Alert firing in
#{
args
[
:project_name
]
}
"
)
end
end
describe
'#attachments'
do
it
'returns an array of one'
do
expect
(
subject
.
attachments
).
to
be_a
(
Array
)
expect
(
subject
.
attachments
.
size
).
to
eq
(
1
)
end
it
'contains the correct attributes'
do
attachments_item
=
subject
.
attachments
.
first
expect
(
attachments_item
).
to
have_key
(
:title
)
expect
(
attachments_item
).
to
have_key
(
:title_link
)
expect
(
attachments_item
).
to
have_key
(
:color
)
expect
(
attachments_item
).
to
have_key
(
:fields
)
end
it
'returns the correct color'
do
expect
(
subject
.
attachments
.
first
[
:color
]).
to
eq
(
"#C95823"
)
end
it
'returns the correct attachment fields'
do
attachments_item
=
subject
.
attachments
.
first
fields
=
attachments_item
[
:fields
].
map
{
|
h
|
h
[
:title
]
}
expect
(
fields
).
to
match_array
([
'Severity'
,
'Events'
,
'Status'
,
'Start time'
])
end
end
end
spec/models/service_spec.rb
View file @
a80a29d6
...
...
@@ -114,6 +114,20 @@ describe Service do
expect
(
described_class
.
confidential_note_hooks
.
count
).
to
eq
0
end
end
describe
'.alert_hooks'
do
it
'includes services where alert_events is true'
do
create
(
:service
,
active:
true
,
alert_events:
true
)
expect
(
described_class
.
alert_hooks
.
count
).
to
eq
1
end
it
'excludes services where alert_events is false'
do
create
(
:service
,
active:
true
,
alert_events:
false
)
expect
(
described_class
.
alert_hooks
.
count
).
to
eq
0
end
end
end
describe
"Test Button"
do
...
...
spec/services/alert_management/process_prometheus_alert_service_spec.rb
View file @
a80a29d6
...
...
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec
.
describe
AlertManagement
::
ProcessPrometheusAlertService
do
let_it_be
(
:project
)
{
create
(
:project
)
}
before
do
allow
(
ProjectServiceWorker
).
to
receive
(
:perform_async
)
end
describe
'#execute'
do
subject
(
:execute
)
{
described_class
.
new
(
project
,
nil
,
payload
).
execute
}
...
...
@@ -47,6 +51,12 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
end
end
it
'does not executes the alert service hooks'
do
expect
(
alert
).
not_to
receive
(
:execute_services
)
subject
end
context
'when status change did not succeed'
do
before
do
allow
(
AlertManagement
::
Alert
).
to
receive
(
:for_fingerprint
).
and_return
([
alert
])
...
...
@@ -72,6 +82,26 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
it
'creates a new alert'
do
expect
{
execute
}.
to
change
{
AlertManagement
::
Alert
.
where
(
project:
project
).
count
}.
by
(
1
)
end
it
'executes the alert service hooks'
do
slack_service
=
create
(
:service
,
type:
'SlackService'
,
project:
project
,
alert_events:
true
,
active:
true
)
subject
expect
(
ProjectServiceWorker
).
to
have_received
(
:perform_async
).
with
(
slack_service
.
id
,
an_instance_of
(
Hash
))
end
context
'feature flag disabled'
do
before
do
stub_feature_flags
(
alert_slack_event:
false
)
end
it
'does not execute the alert service hooks'
do
subject
expect
(
ProjectServiceWorker
).
not_to
have_received
(
:perform_async
)
end
end
end
context
'when alert cannot be created'
do
...
...
spec/services/projects/alerting/notify_service_spec.rb
View file @
a80a29d6
...
...
@@ -8,12 +8,17 @@ describe Projects::Alerting::NotifyService do
before
do
# We use `let_it_be(:project)` so we make sure to clear caches
project
.
clear_memoization
(
:licensed_feature_available
)
allow
(
ProjectServiceWorker
).
to
receive
(
:perform_async
)
end
shared_examples
'processes incident issues'
do
|
amount
|
let
(
:create_incident_service
)
{
spy
}
let
(
:new_alert
)
{
instance_double
(
AlertManagement
::
Alert
,
id:
503
,
persisted?:
true
)
}
before
do
allow
(
new_alert
).
to
receive
(
:execute_services
)
end
it
'processes issues'
do
expect
(
AlertManagement
::
Alert
)
.
to
receive
(
:create
)
...
...
@@ -138,6 +143,25 @@ describe Projects::Alerting::NotifyService do
)
end
it
'executes the alert service hooks'
do
slack_service
=
create
(
:service
,
type:
'SlackService'
,
project:
project
,
alert_events:
true
,
active:
true
)
subject
expect
(
ProjectServiceWorker
).
to
have_received
(
:perform_async
).
with
(
slack_service
.
id
,
an_instance_of
(
Hash
))
end
context
'feature flag disabled'
do
before
do
stub_feature_flags
(
alert_slack_event:
false
)
end
it
'does not executes the alert service hooks'
do
subject
expect
(
ProjectServiceWorker
).
not_to
have_received
(
:perform_async
)
end
end
context
'existing alert with same fingerprint'
do
let!
(
:existing_alert
)
{
create
(
:alert_management_alert
,
project:
project
,
fingerprint:
Digest
::
SHA1
.
hexdigest
(
fingerprint
))
}
...
...
@@ -148,6 +172,12 @@ describe Projects::Alerting::NotifyService do
it
'increments the existing alert count'
do
expect
{
subject
}.
to
change
{
existing_alert
.
reload
.
events
}.
from
(
1
).
to
(
2
)
end
it
'does not executes the alert service hooks'
do
subject
expect
(
ProjectServiceWorker
).
not_to
have_received
(
:perform_async
)
end
end
context
'with a minimal payload'
do
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment