Class: Nagira

Inherits:
Sinatra::Base
  • Object
show all
Includes:
OutputTypeable
Defined in:
app/app.rb,
app/routes/get.rb,
app/filters/after.rb,
app/filters/before.rb,
app/parsers/parser.rb,
app/routes/put/host.rb,
app/filters/configure.rb,
app/routes/get/config.rb,
app/routes/get/status.rb,
app/routes/put/status.rb,
app/routes/get/objects.rb,
lib/nagira/hostservice.rb,
app/helpers/put_helpers.rb,
app/loggers/simple_logger.rb,
app/parsers/background_parse.rb,
app/routes/get/status/hostgroups.rb,
app/controllers/api_help_controller.rb,
app/routes/get/status/servicegroups.rb,
app/writers/external_command_writer.rb,
app/controllers/hostgroup_controller.rb,
app/controllers/host_status_controller.rb,
app/controllers/service_status_controler.rb,
app/controllers/servicegroups_controller.rb,
app/controllers/resource_status_controler.rb

Overview

PUT method routes for services status.

Defined Under Namespace

Classes: ApiHelpController, BackgroundParser, HostService, HostStatusController, HostgroupController, Logger, Parser, ResourceStatusController, ServiceStatusController, ServicegroupController, Writer

Instance Method Summary collapse

Methods included from OutputTypeable

#body_with_list, #full?, #list?, #state?

Instance Method Details

#after("ArgumentError") ⇒ Object

Return 400 if result of PUT operation is not success.



37
38
39
40
41
# File 'app/filters/after.rb', line 37

after do
  if request.put? && ! response.body[:result]
    halt [400, response.body.send("to_#{@format}") ]
  end
end

#before("clear data") ⇒ Object

Clear values onf instance variables before start.



45
46
47
48
# File 'app/filters/before.rb', line 45

before do
  @data = []
  @format = @output = nil
end

#after("Return Array for ActiveResouce routes") ⇒ Object



48
49
50
# File 'app/filters/after.rb', line 48

after do
   response.body = response.body.values if @active_resource && response.body.is_a?(Hash)
end

#before('detect ActiveResource mode') ⇒ Object

Detect if this a request for ActiveResource PATH



81
82
83
# File 'app/filters/before.rb', line 81

before do
  @active_resource = request.path_info =~ %r{^#{Nagira::AR_PREFIX}/}
end

#before('find callback name') ⇒ Object

Detects if request is using jQuery JSON-P and sets @callback variable. @callback variable is used if after method and prepends JSON data with callback function name.

Example

GET /_api?callback=jQuery12313123123 # @callback == jQuery12313123123

JSONP support is based on the code from sinatra/jsonp Gem github.com/shtirlic/sinatra-jsonp.



127
128
129
130
131
132
133
# File 'app/filters/before.rb', line 127

before do
  if @format == :json
    ['callback','jscallback','jsonp','jsoncallback'].each do |x|
      @callback = params.delete(x) unless @callback
    end
  end
end

#get_1_objectObject

Get single Nagios object.

Accepted output type modifiers:

  • none

Parameters:

  • :type (String)

    Type is one of Nagios objects like hosts, hostgroupsroups, etc.

  • :name (String)


45
46
47
# File 'app/routes/get/objects.rb', line 45

get "/_objects/:type/:name" do |type,name|
  @objects[type.to_sym][name]
end

#get(/_api)) ⇒ Object

Provide information about API routes



9
10
11
# File 'app/routes/get.rb', line 9

get "/_api" do
  ApiHelpController.get
end

#get("/_config") ⇒ Object

Get Nagios configuration hash form parsing main Nagios configuration file nagios.cfg



8
9
10
# File 'app/routes/get/config.rb', line 8

get "/_config" do
  Parser.config.configuration
end

#get_object_typeObject

Get all objects of type :type

Accepted output type modifiers:

  • /_list : Short list of available objects, depending on the current request context: hosts, services, etc.

Parameters:

  • :type (String)

    Type is one of Nagios objects like hosts, hostgroupsroups, etc.



30
31
32
# File 'app/routes/get/objects.rb', line 30

get "/_objects/:type" do |type|
  body_with_list @objects[type.to_sym]
end

#get_objectsObject

Objects routes

Get full list of Nagios objects. Returns hash containing all configured objects in Nagios: hosts, hostgroups, services, contacts. etc.

Accepted output type modifiers:

  • /_list : Short list of available objects, depending on the current request context: hosts, services, etc.



16
17
18
# File 'app/routes/get/objects.rb', line 16

get "/_objects" do
  body_with_list @objects
end

#get(/_runtime)) ⇒ Object

Print out nagira runtime configuration



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'app/routes/get.rb', line 18

get "/_runtime" do
  {
    application: self.class,
    version: VERSION,
    runtime: {
      environment: Nagira.settings.environment,
      home: ENV['HOME'],
      user: ENV['LOGNAME'],
      nagiosFiles: Parser.state.to_h.keys.map {  |x| {  x:  Parser.state.to_h[x].path }},
      commandFile: Writer.commands.path
    }
  }
end

#get(/)) ⇒ Object

Returns application information: name, version, github repository.



36
37
38
39
40
41
42
43
# File 'app/routes/get.rb', line 36

get "/" do
  {
    :application => self.class,
    :version => VERSION,
    :source => GITHUB,
    :apiUrl => request.url.sub(/\/$/,'') + "/_api",
  }
end

#get_statusObject

Return all hosts status.

If no output modifier provided, outputs full hosttatus information for each host. Not including services information. When _full modifier is provided data include hoststatus, servicestatus and all comments (servicecomments and hostcomments) for hosts.

Alias: get /_status is the same thing as get /_status/_hosts with ActiveResource compatibility, i.e. for */_hosts request Nagira returns array instead of hash.

Accepted output type modifiers:

  • /_state - Instead of full status information send only current state. For hosts up/down, for services OK, Warn, Critical, Unknown (0,1,2-1)

  • /_list : Short list of available objects, depending on the current request context: hosts, services, etc.

  • /_full - Show full status information. When used in /_status/_full call will display full hoststaus and servicestatus information for each host.

Support for (see API):

  • plural resources: N/A

  • object access by ID: N/A



73
74
75
# File 'app/routes/get/status.rb', line 73

get %r{^/_status(/_hosts)?$} do
  HostStatusController.new(@status, output: @output).get
end

#get_status_hostgroupObject

Return full status of the hostgroup: including host status and service status.



9
10
11
# File 'app/routes/get/status/hostgroups.rb', line 9

get "/_status/_hostgroup/:hostgroup" do |hostgroup|
  HostgroupController.new(hostgroup).full
end

#get("/_status/_hostgroup/: hostgroup/_host") ⇒ Object

Endpoint:

  • GET /_status/_hostgroup/:host



29
30
31
# File 'app/routes/get/status/hostgroups.rb', line 29

get "/_status/_hostgroup/:hostgroup/_host" do |hostgroup|
  HostgroupController.new(hostgroup).host_status
end

#get_status_hostgroup_serviceObject

Endpoint:

  • GET /_status/_hostgroup/:hostgroup/_service



19
20
21
# File 'app/routes/get/status/hostgroups.rb', line 19

get "/_status/_hostgroup/:hostgroup/_service" do |hostgroup|
  HostgroupController.new(hostgroup).service_status
end

#get_status_hostnameObject

Hoststatus for single host or all services.

Endpoint

  • get “/_status/:hostname”

Accepted output type modifiers:

  • /_state - Instead of full status information send only current state. For hosts up/down, for services OK, Warn, Critical, Unknown (0,1,2-1)

Support for:

  • plural resources: N/A

  • object access by ID: NO (TODO)

Parameters:

  • :hostname (String)

    Configured Nagios hostname



94
95
96
# File 'app/routes/get/status.rb', line 94

get %r{^/_status/(?<hostname>#{hostname_regex})$} do |hostname|
  HostStatusController.new(@status, output: @output, hostname: hostname).get
end

#get_status_hostname_servicesObject

Endpoints:

  • GET /_status/:hostname/_services

  • GET /_status/:hostname/_hostcomments

  • GET /_status/:hostname/_servicecomments

Read services, hostcomments or servicecomments for single host.

Accepted output type modifiers:

  • /_state - Instead of full status information send only current state. For hosts up/down, for services OK, Warn, Critical, Unknown (0,1,2-1)

  • /_list : Short list of available objects, depending on the current request context: hosts, services, etc.

  • /_full - Show full status information. When used in /_status/_full call will display full hoststaus and servicestatus information for each host.

Parameters:

  • :hostname (String)

    Configured Nagios hostname



41
42
43
44
45
46
47
48
# File 'app/routes/get/status.rb', line 41

get %r{^/_status/(?<hostname>#{hostname_regex})/_(?<resource>(services|hostcomments|servicecomments))$} do |hostname,resource|

  # hostname = hostname.to_i if hostname =~ /^\d+$/
  ResourceStatusController.new(
    @status, hostname: hostname, output: @output, resource: resource
  ).get

end

#get("/_status/: hostname/_services/:service_name") ⇒ Object

Full or short status information for single service on single host.

Accepted output type modifiers:

  • /_state - Instead of full status information send only current state. For hosts up/down, for services OK, Warn, Critical, Unknown (0,1,2-1)

Parameters:

  • :hostname (String)

    Configured Nagios hostname

  • :service_name (String)

    Configured Nagios service for the host



19
20
21
22
23
# File 'app/routes/get/status.rb', line 19

get "/_status/:hostname/_services/:service_name" do |hostname,service|
  ServiceStatusController.new(
    @status, hostname: hostname, service_name: service, output: @output
  ).get
end

#get_status_servicegroupObject

Endpoint:

  • GET /_status/_servicegroup/:servicegroup

Supported extensions: _state, _list



12
13
14
# File 'app/routes/get/status/servicegroups.rb', line 12

get "/_status/_servicegroup/:servicegroup" do |group_name|
  ServicegroupController.new(group_name).send(@output)
end

#after("Object not found or bad request") ⇒ Object

If result-set of object/status search is empty return HTTP 404 . This can happen when you are requesting status for not existing host and/or service.



21
22
23
24
25
26
27
28
29
# File 'app/filters/after.rb', line 21

after do
  if response.body.empty?
    halt [404, {
            :message => "Object not found or bad request",
            :error => "HTTP::Notfound"
          }.send("to_#{@format}")
         ]
  end
end

#before("Parse PUT request body") ⇒ Array

Process the data before on each HTTP request.

Returns:

  • (Array)

    @input Sets @input instance variable.



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'app/filters/before.rb', line 142

before do
  if request.put?
    data = request.body.read
    @input = case @format
            when :json then JSON.parse    data
            when :xml  then Hash.from_xml data
            when :yaml then YAML.load     data
            end
    # Make sure we always return an Array
    @input = [@input] if @input.is_a? Hash
    @input
  end
end

#before("Parse Nagios files") ⇒ Object

Parse nagios files.

Note: *.parse methods are monkey-patched here (if you have required ‘lib/nagira’ above) to set min parsing interval to avoid file paring on each HTTP request. File is parsed only if it was changed and if it was parsed more then 60 (default) seconds ago. See lib/nagira/timed_parse.rb for mor more info.

In development mode use files located under ./test/data directory. This allows to do development on the host where Nagios is notinstalled. If you want to change this edit configuration in config/environment.rb file.

See also comments in config/default.rb file regarding nagios_cfg, status_cfg, objects_cfg.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/filters/before.rb', line 22

before do
  Logger.log("BackgroundParser is not running", :warning) if
    BackgroundParser.configured? && BackgroundParser.dead?

  Parser.parse

  @status = Parser.status['hosts']
  @objects = Parser.objects

  #
  # Add plural keys to use ActiveResource with Nagira
  #
  @objects.keys.each do |singular|
    @objects[singular.to_s.pluralize.to_sym] = @objects[singular]
  end
end

#put("/_host_status/: host_name") ⇒ Object

Same as /_status/:host_name (Not implemented)



44
45
46
# File 'app/routes/put/host.rb', line 44

put "/_host_status/:host_name" do
  "Not implemented: TODO"
end

#put("/_status") ⇒ Object

Submit JSON Hash for multiple services, on multiple hosts.



10
11
12
# File 'app/routes/put/host.rb', line 10

put "/_status" do
  "TODO: Not implemented"
end

#put(/_status/: host_name/_services/:service_description/_return_code/:return_code/_plugin_output/:plugin_output) ⇒ Object

Update single service status on a single host. Use data provided in RESTful path as parameters.

Example

curl  -d "test data" \
  -X PUT http://localhost:4567/_status/viy/_services/PING/_return_code/0/_plugin_output/OK
 # => ok


87
88
89
# File 'app/routes/put/status.rb', line 87

put "/_status/:host_name/_services/:service_description/_return_code/:return_code/_plugin_output/:plugin_output" do
  update_service_status params
end

#put("/_status/: host_name") ⇒ Object

Update hoststatus information only for the given host. URL hostname always override hostname given in the JSON file.

Example

$ curl -i -H "Accept: application/json" -d @host.json -X
    PUT http://localhost:4567/_status/svaroh

  => {"result": true, "object": [{"data": {"host_name":"svaroh",
  "status_code": "0", "plugin_output": "ping OK", "action":
  "PROCESS_HOST_CHECK_RESULT"}, "result":true, "messages": []}]}

Example JSON

{
 "status_code":"0",
 "plugin_output" : "ping OK"
}


35
36
37
# File 'app/routes/put/host.rb', line 35

put "/_status/:host_name" do
  HostStatusController.new({}, hostname: params['host_name']).put(@input.first)
end

#put("/_status/: host_name/_services") ⇒ Object

Update multiple services on the same host.

Hostname from URL always overrides host_name if it’s is provided in the JSON data.

Example return JSON data

$ curl -i -H "Accept: application/json" -d @dat_m.json -X PUT
http://localhost:4567/_status/svaroh/_services

  {"result"=>true,
   "object"=>
    [{"data"=>
       {"return_code"=>0,
        "plugin_output"=>"All OK",
        "service_description"=>"PING",
        "host_name"=>"archive",
        "action"=>"PROCESS_SERVICE_CHECK_RESULT"},
      "result"=>true,
      "messages"=>[]}]}

Example JSON for submit

All attributes provided in the example below are requried for host service status information:

  • host_name

  • service_description

  • return_code

  • plugin_output

    [{ "host_name":"viy",
       "service_description":"PING",
       "return_code":"0",
       "plugin_output":"64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.046 ms "
      },
    
    {"host_name":"svaroh",
       "service_description":"Apache",
       "return_code":"2",
       "plugin_output":"HTTP GEt failed"
       }
      ]
    


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/routes/put/status.rb', line 54

put "/_status/:host_name/_services" do |hostname|

  data, result = [], true

  @input.each do |datum|
    # FIXME - this calls update for each service. Should be batching them together
    update = update_service_status(
      datum.merge({
        'host_name' => hostname
      })
                                    )
    data << update[:object].first
    result &&= update[:result]
  end
  { result: result, object: data }
end

#after("Return formatted data") ⇒ Object

If it’s a JSON-P request, return its data with prepended @callback function name. JSONP request is detected by before method.

If no callback paramete given, then simply return formatted data as XML, JSON, or YAML in response body.

Example

$ curl  'http://localhost:4567/?callback=test'
    test(["{\"application\":\"Nagira\",\"version\":\"0.1.3\",\"url\":\"http://dmytro.github.com/nagira/\"}"])


67
68
69
70
71
72
73
74
75
# File 'app/filters/after.rb', line 67

after do
  body(
       if @callback
         "#{@callback.to_s} (#{response.body.to_json})"
       else
         response.body.send "to_#{@format}"
       end
      )
end

#before("Initial Config") ⇒ Object

Do some necessary tasks at start and then run Sinatra app.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'app/filters/configure.rb', line 11

configure do

  Parser.config   = settings.nagios_cfg
  Parser.status   = settings.status_cfg   || Parser.config.status_file
  Parser.objects  = settings.objects_cfg  || Parser.config.object_cache_file

  Writer.commands = settings.command_file || Parser.config.command_file

  BackgroundParser.ttl    = ::DEFAULT[:ttl].to_i
  BackgroundParser.start  = ::DEFAULT[:start_background_parser]

  Logger.log "Starting Nagira application"
  Logger.log "Version #{Nagira::VERSION}"
  Logger.log "Running in #{Nagira.settings.environment} environment"

  Parser.state.to_h.keys.each do |x|
    Logger.log "Using nagios #{x} file: #{Parser.state[x].path}"
  end
  Logger.log "Using nagios command file: #{Writer.commands.path}"

  BackgroundParser.run if BackgroundParser.configured?
end

#before("detect format") ⇒ Object

Detect and strip output format extension

Strip extension (@format) from HTTP route and set it as instance variable @format. Valid formats are .xml, .json, .yaml. If format is not specified, it is set to default format (Nagira.settings.format).

@format can be assigned one of the symbols: :xml, :json, :yaml.

Examples

GET /_objects              # => default format
GET /_objects.json         # => :json
GET /_status/_list.yaml    # => :yaml


69
70
71
72
73
# File 'app/filters/before.rb', line 69

before do
  request.path_info.sub!(/#{settings.format_extensions}/, '')
  @format = ($1 || settings.format).to_sym
  content_type "application/#{@format.to_s}"
end

#before('detect output mode') ⇒ Object

Detect output mode modifier

Detect and strip output type from HTTP route. Full list of output types is :list, :state or :full, corresponding to (+/list, /state, /full routes).

Output type defined by route modifier appended to the end of HTTP route. If no output type specfied it is set to :full. Output mode can be followed by format extension (.json, .xml or .yaml).

Examples

GET /_objects/_list     # => :list
GET /_status/_state     # => :state
GET /_status/:hostname  # => :full
GET /_status            # => :normal


107
108
109
110
# File 'app/filters/before.rb', line 107

before do
  request.path_info.sub!(/\/_(list|state|full)$/, '')
  @output = ($1 || :normal).to_sym
end

#update_service_status(params) ⇒ Object

Small helper to submit data to ::Nagios::ExternalCommands object. For status updates sends external coond via ::Nagios::ExternalCommands.send method.



7
8
9
# File 'app/helpers/put_helpers.rb', line 7

def update_service_status params
  Writer.new(:PROCESS_SERVICE_CHECK_RESULT).put params
end