From a97e261ac7a5ca19dc6d2421cb775b8c3e82e707 Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Fri, 2 Nov 2018 07:35:28 +0100 Subject: [PATCH] Improved monitoring controller with amount_check (e. g. monitoring will alert about unusual amount of ticket creation). --- app/controllers/monitoring_controller.rb | 108 +++++++++++++++- config/routes/monitoring.rb | 1 + .../integration/monitoring_controller_test.rb | 121 ++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) diff --git a/app/controllers/monitoring_controller.rb b/app/controllers/monitoring_controller.rb index 55aa22b0f..d99dc7dbf 100644 --- a/app/controllers/monitoring_controller.rb +++ b/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) diff --git a/config/routes/monitoring.rb b/config/routes/monitoring.rb index 637330fac..95e6566f4 100644 --- a/config/routes/monitoring.rb +++ b/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 diff --git a/test/integration/monitoring_controller_test.rb b/test/integration/monitoring_controller_test.rb index 9d0409578..1de1267a3 100644 --- a/test/integration/monitoring_controller_test.rb +++ b/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