Commit e4ba4ccf authored by Tiago Botelho's avatar Tiago Botelho

Handle update and destroy behaviour of metrics to cleanly erase the associated alerts

parent 1caffa13
...@@ -2188,8 +2188,6 @@ ActiveRecord::Schema.define(version: 20180704204006) do ...@@ -2188,8 +2188,6 @@ ActiveRecord::Schema.define(version: 20180704204006) do
t.integer "environment_id", null: false t.integer "environment_id", null: false
t.integer "project_id", null: false t.integer "project_id", null: false
t.integer "prometheus_metric_id", null: false t.integer "prometheus_metric_id", null: false
t.text "name", null: false
t.string "query", null: false
end end
add_index "prometheus_alerts", ["environment_id"], name: "index_prometheus_alerts_on_environment_id", using: :btree add_index "prometheus_alerts", ["environment_id"], name: "index_prometheus_alerts_on_environment_id", using: :btree
......
...@@ -47,7 +47,7 @@ module EE ...@@ -47,7 +47,7 @@ module EE
def update def update
@metric = project.prometheus_metrics.find(params[:id]) # rubocop:disable Gitlab/ModuleWithInstanceVariables @metric = project.prometheus_metrics.find(params[:id]) # rubocop:disable Gitlab/ModuleWithInstanceVariables
@metric.update(metrics_params) # rubocop:disable Gitlab/ModuleWithInstanceVariables @metric = update_metrics_service(@metric).execute # rubocop:disable Gitlab/ModuleWithInstanceVariables
if @metric.persisted? # rubocop:disable Gitlab/ModuleWithInstanceVariables if @metric.persisted? # rubocop:disable Gitlab/ModuleWithInstanceVariables
redirect_to edit_project_service_path(project, ::PrometheusService), redirect_to edit_project_service_path(project, ::PrometheusService),
...@@ -63,7 +63,7 @@ module EE ...@@ -63,7 +63,7 @@ module EE
def destroy def destroy
metric = project.prometheus_metrics.find(params[:id]) metric = project.prometheus_metrics.find(params[:id])
metric.destroy destroy_metrics_service(metric).execute
respond_to do |format| respond_to do |format|
format.html do format.html do
...@@ -77,6 +77,14 @@ module EE ...@@ -77,6 +77,14 @@ module EE
private private
def update_metrics_service(metric)
::Projects::Prometheus::Metrics::UpdateService.new(metric, metrics_params)
end
def destroy_metrics_service(metric)
::Projects::Prometheus::Metrics::DestroyService.new(metric)
end
def metrics_params def metrics_params
params.require(:prometheus_metric).permit(:title, :query, :y_label, :unit, :legend, :group) params.require(:prometheus_metric).permit(:title, :query, :y_label, :unit, :legend, :group)
end end
......
...@@ -60,7 +60,7 @@ module Projects ...@@ -60,7 +60,7 @@ module Projects
private private
def alerts_params def alerts_params
alerts_params = params.permit(:query, :operator, :threshold, :name, :environment_id, :prometheus_metric_id) alerts_params = params.permit(:operator, :threshold, :environment_id, :prometheus_metric_id)
if alerts_params[:operator].present? if alerts_params[:operator].present?
alerts_params[:operator] = PrometheusAlert.operator_to_enum(alerts_params[:operator]) alerts_params[:operator] = PrometheusAlert.operator_to_enum(alerts_params[:operator])
......
class PrometheusAlert < ActiveRecord::Base class PrometheusAlert < ActiveRecord::Base
include AtomicInternalId
OPERATORS_MAP = { OPERATORS_MAP = {
lt: "<", lt: "<",
eq: "=", eq: "=",
...@@ -11,13 +9,13 @@ class PrometheusAlert < ActiveRecord::Base ...@@ -11,13 +9,13 @@ class PrometheusAlert < ActiveRecord::Base
belongs_to :project, required: true, validate: true, inverse_of: :prometheus_alerts belongs_to :project, required: true, validate: true, inverse_of: :prometheus_alerts
belongs_to :prometheus_metric, required: true, validate: true belongs_to :prometheus_metric, required: true, validate: true
validates :name, presence: true
after_save :clear_prometheus_adapter_cache! after_save :clear_prometheus_adapter_cache!
after_destroy :clear_prometheus_adapter_cache! after_destroy :clear_prometheus_adapter_cache!
enum operator: [:lt, :eq, :gt] enum operator: [:lt, :eq, :gt]
delegate :title, :query, to: :prometheus_metric
def self.operator_to_enum(op) def self.operator_to_enum(op)
OPERATORS_MAP.invert.fetch(op) OPERATORS_MAP.invert.fetch(op)
end end
...@@ -32,7 +30,7 @@ class PrometheusAlert < ActiveRecord::Base ...@@ -32,7 +30,7 @@ class PrometheusAlert < ActiveRecord::Base
def to_param def to_param
{ {
"alert" => name, "alert" => title,
"expr" => full_query, "expr" => full_query,
"for" => "5m", "for" => "5m",
"labels" => { "labels" => {
......
...@@ -2,7 +2,7 @@ class PrometheusAlertEntity < Grape::Entity ...@@ -2,7 +2,7 @@ class PrometheusAlertEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
expose :id expose :id
expose :name expose :title
expose :query expose :query
expose :threshold expose :threshold
......
module Projects
module Prometheus
module Metrics
class BaseService
def initialize(metric, params = {})
@metric = metric
@project = metric.project
@params = params.dup
end
protected
attr_reader :metric, :project, :params
def application
metric.prometheus_alert.environment.cluster_prometheus_adapter
end
def schedule_alert_update
::Clusters::Applications::ScheduleUpdateService.new(application, project).execute
end
def has_alert?
metric.prometheus_alert.present?
end
end
end
end
end
module Projects
module Prometheus
module Metrics
class DestroyService < BaseService
def execute
schedule_alert_update if has_alert?
metric.destroy
end
end
end
end
end
module Projects
module Prometheus
module Metrics
class UpdateService < BaseService
def execute
metric.update(params)
schedule_alert_update if requires_alert_update?
metric
end
private
def requires_alert_update?
has_alert? && (changing_title? || changing_query?)
end
def changing_title?
metric.previous_changes.include?(:title)
end
def changing_query?
metric.previous_changes.include?(:query)
end
end
end
end
end
...@@ -10,8 +10,6 @@ class CreatePrometheusAlerts < ActiveRecord::Migration ...@@ -10,8 +10,6 @@ class CreatePrometheusAlerts < ActiveRecord::Migration
t.references :environment, index: true, null: false, foreign_key: { on_delete: :cascade } t.references :environment, index: true, null: false, foreign_key: { on_delete: :cascade }
t.references :project, null: false, foreign_key: { on_delete: :cascade } t.references :project, null: false, foreign_key: { on_delete: :cascade }
t.references :prometheus_metric, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade } t.references :prometheus_metric, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
t.text :name, null: false
t.string :query, null: false
end end
end end
......
...@@ -111,10 +111,8 @@ describe Projects::Prometheus::AlertsController do ...@@ -111,10 +111,8 @@ describe Projects::Prometheus::AlertsController do
stub_licensed_features(prometheus_alerts: false) stub_licensed_features(prometheus_alerts: false)
post :create, project_params( post :create, project_params(
query: "foo",
operator: ">", operator: ">",
threshold: "1", threshold: "1",
name: "bar",
environment_id: environment.id, environment_id: environment.id,
prometheus_metric_id: metric.id prometheus_metric_id: metric.id
) )
...@@ -125,8 +123,8 @@ describe Projects::Prometheus::AlertsController do ...@@ -125,8 +123,8 @@ describe Projects::Prometheus::AlertsController do
it 'creates a new prometheus alert' do it 'creates a new prometheus alert' do
schedule_update_service = spy schedule_update_service = spy
alert_params = { alert_params = {
"name" => "bar", "name" => metric.title,
"query" => "foo", "query" => metric.query,
"operator" => ">", "operator" => ">",
"threshold" => 1.0 "threshold" => 1.0
} }
...@@ -134,10 +132,8 @@ describe Projects::Prometheus::AlertsController do ...@@ -134,10 +132,8 @@ describe Projects::Prometheus::AlertsController do
allow(::Clusters::Applications::ScheduleUpdateService).to receive(:new).and_return(schedule_update_service) allow(::Clusters::Applications::ScheduleUpdateService).to receive(:new).and_return(schedule_update_service)
post :create, project_params( post :create, project_params(
query: "foo",
operator: ">", operator: ">",
threshold: "1", threshold: "1",
name: "bar",
environment_id: environment.id, environment_id: environment.id,
prometheus_metric_id: metric.id prometheus_metric_id: metric.id
) )
...@@ -175,8 +171,8 @@ describe Projects::Prometheus::AlertsController do ...@@ -175,8 +171,8 @@ describe Projects::Prometheus::AlertsController do
} }
expect do expect do
put :update, project_params(id: alert.prometheus_metric_id, name: "bar") put :update, project_params(id: alert.prometheus_metric_id, operator: "<")
end.to change { alert.reload.name }.to("bar") end.to change { alert.reload.operator }.to("lt")
expect(schedule_update_service).to have_received(:execute) expect(schedule_update_service).to have_received(:execute)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment