Browse Source

Initial Check_MK integration.

Martin Edenhofer 7 years ago
parent
commit
24696c00ee

+ 46 - 0
app/assets/javascripts/app/controllers/_integration/check_mk.coffee

@@ -0,0 +1,46 @@
+class Index extends App.ControllerIntegrationBase
+  featureIntegration: 'check_mk_integration'
+  featureName: 'Check_MK'
+  featureConfig: 'check_mk_config'
+  description: [
+    ['This service receives http requests from %s and creates tickets with host and service.', 'Check_MK']
+    ['If the host and service is recovered again, the ticket will be closed automatically.']
+  ]
+
+  render: =>
+    super
+    new App.SettingsForm(
+      area: 'Integration::CheckMK'
+      el: @$('.js-form')
+    )
+
+    new App.ScriptSnipped(
+      el: @$('.js-scriptSnipped')
+      facility: 'check_mk'
+      style: 'bash'
+      content: "#!/bin/bash\n\ncurl -X POST -F 'event_id=123' -F 'host=host1' -F 'service=http' -F 'state=down'  #{App.Config.get('http_type')}://#{App.Config.get('fqdn')}/api/v1/integration/check_mk/#{App.Setting.get('check_mk_token')}"
+      description: [
+        ['To enable %s for sending http requests to %s, you need create "%s" in the admin interface if %s.', 'Check_MK', 'Zammad', 'Event Actions', 'Check_MK']
+      ]
+    )
+
+    new App.HttpLog(
+      el: @$('.js-log')
+      facility: 'check_mk'
+    )
+
+class State
+  @current: ->
+    App.Setting.get('check_mk_integration')
+
+App.Config.set(
+  'IntegrationCheckMk'
+  {
+    name: 'Check_MK'
+    target: '#system/integration/check_mk'
+    description: 'An open source monitoring tool.'
+    controller: Index
+    state: State
+  }
+  'NavBarIntegrations'
+)

+ 8 - 6
app/assets/javascripts/app/controllers/ticket_zoom/sidebar_customer.coffee

@@ -1,7 +1,7 @@
 class SidebarCustomer extends App.Controller
   sidebarItem: =>
     return if !@permissionCheck('ticket.agent')
-    {
+    items = {
       head:    'Customer'
       name:    'customer'
       icon:    'person'
@@ -11,14 +11,16 @@ class SidebarCustomer extends App.Controller
           name:     'customer-change'
           callback: @changeCustomer
         },
-        {
-          title:    'Edit Customer'
-          name:     'customer-edit'
-          callback: @editCustomer
-        },
       ]
       callback: @showCustomer
     }
+    return items if @ticket && @ticket.customer_id == 1
+    items.actions.push {
+      title:    'Edit Customer'
+      name:     'customer-edit'
+      callback: @editCustomer
+    }
+    items
 
   showCustomer: (el) =>
     @el = el

+ 1 - 0
app/assets/javascripts/app/controllers/widget/http_log.coffee

@@ -25,6 +25,7 @@ class App.HttpLog extends App.Controller
   render: =>
     @html App.view('widget/http_log')(
       records: @records
+      description: @description
     )
 
   show: (e) =>

+ 24 - 0
app/assets/javascripts/app/controllers/widget/script_snipped.coffee

@@ -0,0 +1,24 @@
+class App.ScriptSnipped extends App.Controller
+  #events:
+  #  'click .js-record': 'show'
+
+  elements:
+    '.js-code': 'code'
+
+
+  constructor: ->
+    super
+    #@fetch()
+    @records = []
+    @render()
+
+  render: =>
+    @html App.view('widget/script_snipped')(
+      records: @records
+      description: @description
+      style: @style
+      content: @content
+    )
+
+    @code.each (i, block) ->
+      hljs.highlightBlock block

File diff suppressed because it is too large
+ 0 - 0
app/assets/javascripts/app/lib/base/highlight.pack.js


+ 2 - 1
app/assets/javascripts/app/views/integration/base.jst.eco

@@ -10,9 +10,10 @@
 <div class="page-content">
   <% if @description: %>
     <% for item in @description: %>
-      <p><%- @T(item[0], item[1], item[2]) %></p>
+      <p><%- @T(item...) %></p>
     <% end %>
   <% end %>
   <div class="js-form"></div>
+  <div class="js-scriptSnipped"></div>
   <div class="js-log"></div>
 </div>

+ 25 - 21
app/assets/javascripts/app/views/widget/http_log.jst.eco

@@ -1,27 +1,31 @@
 <hr>
-
-  <h2><%- @T('Recent logs') %></h2>
-  <div class="settings-entry">
+<h2><%- @T('Recent logs') %></h2>
+<% if @description: %>
+  <% for item in @description: %>
+    <p><%- @T(item...) %></p>
+  <% end %>
+<% end %>
+<div class="settings-entry">
 <% if !@records.length: %>
-  <table class="settings-list settings-list--stretch settings-list--placeholder">
-    <thead><tr><th><%- @T('No Entries') %>
-  </table>
+<table class="settings-list settings-list--stretch settings-list--placeholder">
+  <thead><tr><th><%- @T('No Entries') %>
+</table>
 <% else: %>
-    <table class="settings-list settings-list--stretch">
-      <thead>
-        <tr>
-          <th width="10%"><%- @T('Direction') %>
-          <th><%- @T('Request') %>
-          <th width="25%"><%- @T('Created at') %>
-      </thead>
-      <tbody>
+  <table class="settings-list settings-list--stretch">
+    <thead>
+      <tr>
+        <th width="10%"><%- @T('Direction') %>
+        <th><%- @T('Request') %>
+        <th width="25%"><%- @T('Created at') %>
+    </thead>
+    <tbody>
 <% for record in @records: %>
-        <tr data-id="<%= record.id %>" class="js-record">
-          <td><%- @T(record.direction) %>
-          <td><a href="#"><%= record.status %> <%= record.method %> <%= record.url %></a>
-          <td><%- @humanTime(record.created_at) %>
+      <tr data-id="<%= record.id %>" class="js-record">
+        <td><%- @T(record.direction) %>
+        <td><a href="#"><%= record.status %> <%= record.method %> <%= record.url %></a>
+        <td><%- @humanTime(record.created_at) %>
 <% end %>
-      </tbody>
-    </table>
+    </tbody>
+  </table>
 <% end %>
-  </div>
+</div>

+ 8 - 0
app/assets/javascripts/app/views/widget/script_snipped.jst.eco

@@ -0,0 +1,8 @@
+<hr>
+<h2><%- @T('Usage') %></h2>
+<% if @description: %>
+  <% for item in @description: %>
+    <p><%- @T(item...) %></p>
+  <% end %>
+<% end %>
+<pre><code class="language-<%- @style %> js-code"><%- @content %></code></pre>

+ 4 - 0
app/controllers/application_controller/handles_errors.rb

@@ -15,22 +15,26 @@ module ApplicationController::HandlesErrors
   def not_found(e)
     logger.error e
     respond_to_exception(e, :not_found)
+    http_log
   end
 
   def unprocessable_entity(e)
     logger.error e
     respond_to_exception(e, :unprocessable_entity)
+    http_log
   end
 
   def internal_server_error(e)
     logger.error e
     respond_to_exception(e, :internal_server_error)
+    http_log
   end
 
   def unauthorized(e)
     error = humanize_error(e.message)
     response.headers['X-Failure'] = error.fetch(:error_human, error[:error])
     respond_to_exception(e, :unauthorized)
+    http_log
   end
 
   private

+ 138 - 0
app/controllers/integration/check_mk_controller.rb

@@ -0,0 +1,138 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+
+class Integration::CheckMkController < ApplicationController
+  skip_before_action :verify_csrf_token
+  before_action :check_configured
+
+  def update
+
+    # check params
+    raise Exceptions::UnprocessableEntity, 'event_id is missing!' if params[:event_id].blank?
+    raise Exceptions::UnprocessableEntity, 'state is missing!' if params[:state].blank?
+    raise Exceptions::UnprocessableEntity, 'host is missing!' if params[:host].blank?
+
+    # search for open ticket
+    auto_close = Setting.get('check_mk_auto_close')
+    auto_close_state_id = Setting.get('check_mk_auto_close_state_id')
+    group_id = Setting.get('check_mk_group_id')
+    state_recovery_match = '(OK|UP)'
+
+    # check if ticket with host is open
+    customer = User.lookup(id: 1)
+
+    # follow up detection by meta data
+    integration = 'check_mk'
+    open_states = Ticket::State.by_category(:open)
+    ticket_ids = Ticket.where(state: open_states).order(created_at: :desc).limit(5000).pluck(:id)
+    ticket_ids_found = []
+    ticket_ids.each { |ticket_id|
+      ticket = Ticket.find_by(id: ticket_id)
+      next if !ticket
+      next if !ticket.preferences
+      next if !ticket.preferences[integration]
+      next if !ticket.preferences[integration]['host']
+      next if ticket.preferences[integration]['host'] != params[:host]
+      next if ticket.preferences[integration]['service'] != params[:service]
+
+      # found open ticket for service+host
+      ticket_ids_found.push ticket.id
+    }
+
+    # new ticket, set meta data
+    title = "#{params[:host]} is #{params[:state]}"
+    body = "EventID: #{params[:event_id]}
+Host: #{params[:host]}
+Service: #{params[:service]}
+State: #{params[:state]}
+Text: #{params[:text]}
+RemoteIP: #{request.remote_ip}
+UserAgent: #{request.env['HTTP_USER_AGENT']}
+"
+
+    # add article
+    if params[:state].present? && ticket_ids_found.present?
+      ticket_ids_found.each { |ticket_id|
+        ticket = Ticket.find_by(id: ticket_id)
+        next if !ticket
+        article = Ticket::Article.create!(
+          ticket_id: ticket_id,
+          type_id: Ticket::Article::Type.find_by(name: 'web').id,
+          sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
+          body: body,
+          subject: title,
+          internal: false,
+        )
+      }
+      if (!auto_close && params[:state].match(/#{state_recovery_match}/i)) || !params[:state].match(/#{state_recovery_match}/i)
+        render json: {
+          result: 'ticket already open, added note',
+          ticket_ids: ticket_ids_found,
+        }
+        return
+      end
+    end
+
+    # check if service is recovered
+    if auto_close && params[:state].present? && params[:state].match(/#{state_recovery_match}/i)
+      if ticket_ids_found.blank?
+        render json: {
+          result: 'no open tickets found, ignore action',
+        }
+        return
+      end
+      state = Ticket::State.lookup(id: auto_close_state_id)
+      ticket_ids_found.each { |ticket_id|
+        ticket = Ticket.find_by(id: ticket_id)
+        next if !ticket
+        ticket.state_id = auto_close_state_id
+        ticket.save!
+      }
+      render json: {
+        result: "closed tickets with ids #{ticket_ids_found.join(',')}",
+        ticket_ids: ticket_ids_found,
+      }
+      return
+    end
+
+    ticket = Ticket.create!(
+      group_id: group_id,
+      customer_id: customer.id,
+      title: title,
+      preferences: {
+        check_mk: {
+          host: params[:host],
+          service: params[:service],
+        },
+      }
+    )
+    article = Ticket::Article.create!(
+      ticket_id: ticket.id,
+      type_id: Ticket::Article::Type.find_by(name: 'web').id,
+      sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
+      body: body,
+      subject: title,
+      internal: false,
+    )
+
+    render json: {
+      result: "new ticket created (ticket id: #{ticket.id})",
+      ticket_id: ticket.id,
+      ticket_number: ticket.number,
+    }
+  end
+
+  private
+
+  def check_configured
+    http_log_config facility: 'check_mk'
+
+    if !Setting.get('check_mk_integration')
+      raise Exceptions::UnprocessableEntity, 'Feature is disable, please contact your admin to enable it!'
+    end
+
+    if Setting.get('check_mk_token') != params[:token]
+      raise Exceptions::UnprocessableEntity, 'Invalid token!'
+    end
+  end
+
+end

Some files were not shown because too many files changed in this diff