Browse Source

Improved monitoring controller with amount_check (e. g. monitoring will alert about unusual amount of ticket creation).

Martin Edenhofer 6 years ago
parent
commit
a97e261ac7

+ 107 - 1
app/controllers/monitoring_controller.rb

@@ -1,7 +1,7 @@
 # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
 
 class MonitoringController < ApplicationController
-  prepend_before_action -> { authentication_check(permission: 'admin.monitoring') }, except: %i[health_check status]
+  prepend_before_action -> { authentication_check(permission: 'admin.monitoring') }, except: %i[health_check status amount_check]
   skip_before_action :verify_csrf_token
 
 =begin
@@ -239,6 +239,112 @@ curl http://localhost/api/v1/monitoring/status?token=XXX
     render json: status
   end
 
+=begin
+
+get counts about created ticket in certain time slot. s, m, h and d possible.
+
+Resource:
+
+GET /api/v1/monitoring/amount_check?token=XXX&max_warning=2000&max_critical=3000&periode=1h
+
+GET /api/v1/monitoring/amount_check?token=XXX&min_warning=2000&min_critical=3000&periode=1h
+
+GET /api/v1/monitoring/amount_check?token=XXX&periode=1h
+
+Response:
+{
+  "state": "ok",
+  "message": "",
+  "count": 123,
+}
+
+{
+  "state": "warning",
+  "message": "limit of 2000 tickets in 1h reached",
+  "count": 123,
+}
+
+{
+  "state": "critical",
+  "message": "limit of 3000 tickets in 1h reached",
+  "count": 123,
+}
+
+Test:
+curl http://localhost/api/v1/monitoring/amount_check?token=XXX&max_warning=2000&max_critical=3000&periode=1h
+
+curl http://localhost/api/v1/monitoring/amount_check?token=XXX&min_warning=2000&min_critical=3000&periode=1h
+
+curl http://localhost/api/v1/monitoring/amount_check?token=XXX&periode=1h
+
+=end
+
+  def amount_check
+    token_or_permission_check
+
+    raise Exceptions::UnprocessableEntity, 'periode is missing!' if params[:periode].blank?
+
+    scale = params[:periode][-1, 1]
+    raise Exceptions::UnprocessableEntity, 'periode need to have s, m, h or d as last!' if scale !~ /^(s|m|h|d)$/
+
+    periode = params[:periode][0, params[:periode].length - 1]
+    raise Exceptions::UnprocessableEntity, 'periode need to be an integer!' if periode.to_i.zero?
+
+    if scale == 's'
+      created_at = Time.zone.now - periode.to_i.seconds
+    elsif scale == 'm'
+      created_at = Time.zone.now - periode.to_i.minutes
+    elsif scale == 'h'
+      created_at = Time.zone.now - periode.to_i.hours
+    elsif scale == 'd'
+      created_at = Time.zone.now - periode.to_i.days
+    end
+
+    map = [
+      { param: :max_critical, notice: 'critical', type: 'gt' },
+      { param: :min_critical, notice: 'critical', type: 'lt' },
+      { param: :max_warning, notice: 'warning', type: 'gt' },
+      { param: :min_warning, notice: 'warning', type: 'lt' },
+    ]
+    result = {}
+    map.each do |row|
+      next if params[row[:param]].blank?
+      raise Exceptions::UnprocessableEntity, "#{row[:param]} need to be an integer!" if params[row[:param]].to_i.zero?
+
+      count = Ticket.where('created_at >= ?', created_at).count
+
+      if row[:type] == 'gt'
+        if count > params[row[:param]].to_i
+          result = {
+            state: row[:notice],
+            message: "The limit of #{params[row[:param]]} was exceeded with #{count} in the last #{params[:periode]}",
+            count: count,
+          }
+          break
+        end
+        next
+      end
+      next if count > params[row[:param]].to_i
+
+      result = {
+        state: row[:notice],
+        message: "The minimum of #{params[row[:param]]} was undercut by #{count} in the last #{params[:periode]}",
+        count: count,
+      }
+      break
+    end
+
+    if result.blank?
+      result = {
+        state: 'ok',
+        message: '',
+        count: Ticket.where('created_at >= ?', created_at).count,
+      }
+    end
+
+    render json: result
+  end
+
   def token
     access_check
     token = SecureRandom.urlsafe_base64(40)

+ 1 - 0
config/routes/monitoring.rb

@@ -3,6 +3,7 @@ Zammad::Application.routes.draw do
 
   match api_path + '/monitoring/health_check',         to: 'monitoring#health_check',        via: :get
   match api_path + '/monitoring/status',               to: 'monitoring#status',              via: :get
+  match api_path + '/monitoring/amount_check',         to: 'monitoring#amount_check',        via: :get
   match api_path + '/monitoring/token',                to: 'monitoring#token',               via: :post
   match api_path + '/monitoring/restart_failed_jobs',  to: 'monitoring#restart_failed_jobs', via: :post
 

+ 121 - 0
test/integration/monitoring_controller_test.rb

@@ -692,4 +692,125 @@ class MonitoringControllerTest < ActionDispatch::IntegrationTest
     # cleanup
     Delayed::Job.delete_all
   end
+
+  test '11 check amount' do
+    Ticket.destroy_all
+
+    # amount_check - ok
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('ok', result['state'])
+    assert_equal('', result['message'])
+    assert_equal(0, result['count'])
+
+    Ticket.destroy_all
+    (1..6).each do |i|
+      Ticket.create!(
+        title: "Ticket-#{i}",
+        group: Group.lookup(name: 'Users'),
+        customer_id: 1,
+        state: Ticket::State.lookup(name: 'new'),
+        priority: Ticket::Priority.lookup(name: '2 normal'),
+        updated_by_id: 1,
+        created_by_id: 1,
+      )
+      travel 10.seconds
+    end
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&min_warning=10&min_critical=8", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('critical', result['state'])
+    assert_equal('The minimum of 8 was undercut by 6 in the last 1h', result['message'])
+    assert_equal(6, result['count'])
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&min_warning=7&min_critical=2", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('warning', result['state'])
+    assert_equal('The minimum of 7 was undercut by 6 in the last 1h', result['message'])
+    assert_equal(6, result['count'])
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&max_warning=10&max_critical=20", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('ok', result['state'])
+    assert_equal('', result['message'])
+    assert_equal(6, result['count'])
+
+    (1..6).each do |i|
+      Ticket.create!(
+        title: "Ticket-#{i}",
+        group: Group.lookup(name: 'Users'),
+        customer_id: 1,
+        state: Ticket::State.lookup(name: 'new'),
+        priority: Ticket::Priority.lookup(name: '2 normal'),
+        updated_by_id: 1,
+        created_by_id: 1,
+      )
+      travel 1.second
+    end
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&max_warning=10&max_critical=20", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('warning', result['state'])
+    assert_equal('The limit of 10 was exceeded with 12 in the last 1h', result['message'])
+    assert_equal(12, result['count'])
+
+    (1..10).each do |i|
+      Ticket.create!(
+        title: "Ticket-#{i}",
+        group: Group.lookup(name: 'Users'),
+        customer_id: 1,
+        state: Ticket::State.lookup(name: 'new'),
+        priority: Ticket::Priority.lookup(name: '2 normal'),
+        updated_by_id: 1,
+        created_by_id: 1,
+      )
+      travel 1.second
+    end
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&max_warning=10&max_critical=20", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('critical', result['state'])
+    assert_equal('The limit of 20 was exceeded with 22 in the last 1h', result['message'])
+    assert_equal(22, result['count'])
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('ok', result['state'])
+    assert_equal('', result['message'])
+    assert_equal(22, result['count'])
+
+    travel 2.hours
+
+    get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h", params: {}, headers: @headers
+    assert_response(200)
+
+    result = JSON.parse(@response.body)
+    assert_equal(Hash, result.class)
+    assert_equal('ok', result['state'])
+    assert_equal('', result['message'])
+    assert_equal(0, result['count'])
+
+  end
+
 end