nagira 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +11 -0
  3. data/Rakefile +1 -1
  4. data/app/app.rb +44 -298
  5. data/app/concerns/host_status_name_concerneable.rb +18 -0
  6. data/app/concerns/output_typeable.rb +22 -0
  7. data/app/controllers/api_help_controller.rb +25 -0
  8. data/app/controllers/host_status_controller.rb +82 -0
  9. data/{lib/nagira/hostgroup.rb → app/controllers/hostgroup_controller.rb} +1 -1
  10. data/app/controllers/resource_status_controler.rb +65 -0
  11. data/app/controllers/service_status_controler.rb +50 -0
  12. data/{lib/nagira/servicegroup.rb → app/controllers/servicegroups_controller.rb} +1 -1
  13. data/app/filters/after.rb +76 -0
  14. data/app/filters/before.rb +156 -0
  15. data/app/filters/configure.rb +34 -0
  16. data/app/helpers/put_helpers.rb +11 -0
  17. data/{lib/nagira → app/loggers}/simple_logger.rb +0 -0
  18. data/{lib/nagira → app/parsers}/background_parse.rb +0 -0
  19. data/{lib/nagira → app/parsers}/parser.rb +1 -9
  20. data/app/routes/get.rb +50 -0
  21. data/app/routes/get/config.rb +11 -0
  22. data/app/{get → routes/get}/objects.rb +4 -24
  23. data/app/routes/get/status.rb +98 -0
  24. data/app/{get → routes/get}/status/hostgroups.rb +3 -14
  25. data/app/routes/get/status/servicegroups.rb +16 -0
  26. data/app/{put → routes/put}/host.rb +1 -4
  27. data/app/{put → routes/put}/status.rb +13 -20
  28. data/app/writers/external_command_writer.rb +52 -0
  29. data/bin/nagira +1 -1
  30. data/config/defaults.rb +20 -12
  31. data/config/environment.rb +2 -1
  32. data/lib/nagira/timed_parse.rb +1 -1
  33. data/spec/01_background_parser.rb +5 -5
  34. data/spec/01_data_format/01_nagira_response_spec.rb +6 -6
  35. data/spec/01_data_format/02_0_status_spec.rb +1 -1
  36. data/spec/01_data_format/02_nagira_data_spec.rb +8 -8
  37. data/spec/01_data_format/03_api_spec.rb +3 -3
  38. data/spec/get/status/comments_spec.rb +2 -2
  39. data/spec/get/status/endpoints_spec.rb +11 -11
  40. data/spec/get/status/hostgroup.rb +3 -3
  41. data/spec/get/status/hosts_spec.rb +1 -1
  42. data/spec/get/status/servicegroup.rb +4 -4
  43. data/spec/get/status/services_spec.rb +1 -1
  44. data/spec/put/host_spec.rb +4 -4
  45. data/spec/put/status_spec.rb +5 -5
  46. data/spec/put/support.rb +3 -3
  47. data/spec/spec_helper.rb +3 -3
  48. data/version.txt +1 -1
  49. metadata +70 -60
  50. data/app/get/config.rb +0 -24
  51. data/app/get/status.rb +0 -189
  52. data/app/get/status/servicegroups.rb +0 -28
  53. data/app/put.rb +0 -53
  54. data/lib/nagira.rb +0 -67
@@ -0,0 +1,22 @@
1
+ module OutputTypeable
2
+ def list?
3
+ @output == :list
4
+ end
5
+
6
+ def state?
7
+ @output == :state
8
+ end
9
+
10
+ def full?
11
+ @output == :full
12
+ end
13
+
14
+ def body_with_list(body)
15
+ if list?
16
+ body.keys
17
+ else
18
+ body
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,25 @@
1
+ class Nagira < Sinatra::Base
2
+
3
+ # Parse routes, exposed by Sinatra and build human readable list of
4
+ # API endpoints.
5
+ class ApiHelpController
6
+ # Get all routes that Nagira provides.
7
+ def self.get
8
+ api = { }
9
+
10
+ param_regex = Regexp.new '\(\[\^\\\\\/\?\#\]\+\)'
11
+ Nagira.routes.keys.each do |method|
12
+ api[method] ||= []
13
+ Nagira.routes[method].each do |r|
14
+ path = r[0].inspect[3..-3]
15
+ r[1].each do |parm|
16
+ path.sub!(param_regex,":#{parm}")
17
+ end
18
+ path.gsub!('\\','')
19
+ api[method] << path unless path.empty?
20
+ end
21
+ end
22
+ api
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,82 @@
1
+ class Nagira < Sinatra::Base
2
+ class HostStatusController
3
+ include OutputTypeable
4
+
5
+ def initialize(status, output: nil, hostname: nil)
6
+ @status = status
7
+ @output = output
8
+ @hostname = hostname
9
+ @http_status = 200
10
+ end
11
+ attr_accessor :http_status
12
+
13
+ # Type of the output for data: full, normal, state or list
14
+ attr_accessor :output
15
+
16
+ # [optional] hostname, if not given then return data for all hosts
17
+ attr_accessor :hostname
18
+
19
+ # Get host status, depending on the type of output required: full,
20
+ # normal, state or list.
21
+ def get
22
+ body = case
23
+ when full? ; then status
24
+ when state? ; then state
25
+ when list? ; then list
26
+
27
+ else normal
28
+ end
29
+ [@http_status, body]
30
+ end
31
+
32
+ # Update host status
33
+ def put(params)
34
+ Writer.new(:PROCESS_HOST_CHECK_RESULT)
35
+ .put(with_host(params))
36
+ end
37
+
38
+ def with_host(params)
39
+ params.merge({'host_name' => hostname})
40
+ end
41
+
42
+ # Status data: for all hosts or single host if hostname provided.
43
+ #
44
+ # @return [Hash] Nagios parsed data (Parser.status)
45
+ def status
46
+ if hostname
47
+ { hostname => @status[hostname] }
48
+ else
49
+ @status
50
+ end
51
+ .tap { |x| @http_status = 404 if x.values.compact.empty? }
52
+ end
53
+
54
+ private
55
+
56
+ # List of hosts
57
+ def list
58
+ status.keys
59
+ end
60
+
61
+ # Short state of the host: only hostname and state
62
+ def state
63
+ normal.inject({ }) { |hash,elem|
64
+ hash[elem.first] = elem.last.slice("host_name", "current_state")
65
+ hash
66
+ }
67
+ end
68
+
69
+ # Normal is 'reduced' hoststate: excluding services, i.e. only
70
+ # hoststate
71
+ def normal
72
+ status.inject({ }) do |hash,elem|
73
+ hash[elem.first] = elem.last.try(:[], 'hoststatus')
74
+ hash
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+
82
+ # LocalWords: hoststate hoststatus
@@ -1,5 +1,5 @@
1
1
  class Nagira < Sinatra::Base
2
- class Hostgroup
2
+ class HostgroupController
3
3
  attr_reader :objects, :status, :name, :hostgroup, :data
4
4
 
5
5
  def initialize(name)
@@ -0,0 +1,65 @@
1
+ class Nagira < Sinatra::Base
2
+ class ResourceStatusController
3
+
4
+ include OutputTypeable
5
+
6
+ # @param nagios_status [Hash] output of the Nagios status file parser
7
+ # @param output [Symbol(:state, :list)] Output data: full, short state or list
8
+ # @param hostname [String]
9
+ # @param service_name [String]
10
+ #
11
+ # @param resource [String] Resource to be reported. Currently
12
+ # supported 'servicestatus', 'servicecomments', 'hostcomments'
13
+ def initialize(nagios_status, output: nil, hostname: nil, service_name: nil, resource: "servicestatus")
14
+
15
+ @nagios_status = nagios_status
16
+ @output = output
17
+ @hostname = hostname
18
+ @service_name = service_name
19
+ @resource = if resource == 'services'
20
+ "servicestatus"
21
+ else
22
+ resource
23
+ end
24
+ end
25
+
26
+ # Return status of the resource
27
+ def get
28
+ case
29
+ when state?; then slice
30
+ when list?; then list
31
+ else
32
+ with_service_name
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ # Narrow the status hash to include only 3 keys host_name,
39
+ # current_state and service_description
40
+ def slice
41
+ with_service_name.inject({ }) do |hash, elem|
42
+ hash[elem.first] = elem.last.slice("host_name", "current_state", "service_description")
43
+ hash
44
+ end
45
+ end
46
+
47
+ #
48
+ # @return [Array] List of resources (services, servicecomments).
49
+ #
50
+ # Note: _hostcomments is an Array, return full array if status
51
+ # data structure is not Hash.
52
+ def list
53
+ if status.respond_to? :keys
54
+ status.keys
55
+ else
56
+ status
57
+ end
58
+ end
59
+
60
+ include HostStatusNameConcerneable
61
+
62
+ end
63
+ end
64
+
65
+ # LocalWords: param servicestatus servicecomments hostcomments
@@ -0,0 +1,50 @@
1
+ class Nagira < Sinatra::Base
2
+ class ServiceStatusController
3
+
4
+ include OutputTypeable
5
+
6
+ # @param nagios_status [Hash] output of the Nagios status file parser
7
+ # @param output [Symbol(:state)] Output data: full or short state
8
+ # @param hostname [String]
9
+ # @param service_name [String]
10
+ def initialize(nagios_status, output: nil, hostname: nil, service_name: nil)
11
+
12
+ @nagios_status = nagios_status
13
+ @output = output
14
+ @hostname = hostname
15
+ @service_name = service_name
16
+ @resource = "servicestatus"
17
+ end
18
+
19
+ # Read all statuses of the hosts' services. Format output: full
20
+ # service state hash, or state only: name and state.
21
+ def get
22
+ case
23
+ when state?
24
+ with_service_name
25
+ .values
26
+ .first
27
+ .slice("host_name", "current_state")
28
+ else
29
+ with_service_name
30
+ end
31
+ end
32
+
33
+ def put(params)
34
+ Writer.new(:PROCESS_SERVICE_CHECK_RESULT).put with_service_and_host(params)
35
+ end
36
+
37
+ def with_service_and_host(params)
38
+ params.merge({
39
+ 'service_description' => @service_name,
40
+ 'host_name' => @hostname
41
+ })
42
+ end
43
+
44
+ private
45
+ include HostStatusNameConcerneable
46
+
47
+ end
48
+ end
49
+
50
+ # LocalWords: param servicestatus
@@ -1,5 +1,5 @@
1
1
  class Nagira < Sinatra::Base
2
- class Servicegroup
2
+ class ServicegroupController
3
3
 
4
4
  ##
5
5
  # Single member of servicegroup. In Nagios configuration it is
@@ -0,0 +1,76 @@
1
+ class Nagira < Sinatra::Base
2
+ # Bad request. If you are requesting for the route that does not
3
+ # exist.
4
+ after do
5
+ if response.status == 404
6
+ halt [404, {
7
+ :message => "Bad route or request",
8
+ :error => "HTTP::Notfound"
9
+ }.send("to_#{@format}")
10
+ ]
11
+ end
12
+ end
13
+ ##
14
+ # @method object_not_found
15
+ # @overload after("Object not found or bad request")
16
+ #
17
+ # If result-set of object/status search is empty return HTTP 404 .
18
+ # This can happen when you are requesting status for not existing
19
+ # host and/or service.
20
+ #
21
+ after do
22
+ if response.body.empty?
23
+ halt [404, {
24
+ :message => "Object not found or bad request",
25
+ :error => "HTTP::Notfound"
26
+ }.send("to_#{@format}")
27
+ ]
28
+ end
29
+ end
30
+
31
+ ##
32
+ # @method argument_error
33
+ # @overload after("ArgumentError")
34
+ #
35
+ # Return 400 if result of PUT operation is not success.
36
+ #
37
+ after do
38
+ if request.put? && ! response.body[:result]
39
+ halt [400, response.body.send("to_#{@format}") ]
40
+ end
41
+ end
42
+
43
+ ##
44
+ # @method convert_to_active_resource
45
+ # @overload after("Return Array for ActiveResouce routes")
46
+ #
47
+ #
48
+ after do
49
+ response.body = response.body.values if @active_resource && response.body.is_a?(Hash)
50
+ end
51
+
52
+ ##
53
+ # @method return_jsonp_data
54
+ # @overload after("Return formatted data")
55
+ #
56
+ # If it's a JSON-P request, return its data with prepended @callback
57
+ # function name. JSONP request is detected by +before+ method.
58
+ #
59
+ # If no callback paramete given, then simply return formatted data
60
+ # as XML, JSON, or YAML in response body.
61
+ #
62
+ # = Example
63
+ #
64
+ # $ curl 'http://localhost:4567/?callback=test'
65
+ # test(["{\"application\":\"Nagira\",\"version\":\"0.1.3\",\"url\":\"http://dmytro.github.com/nagira/\"}"])
66
+ #
67
+ after do
68
+ body(
69
+ if @callback
70
+ "#{@callback.to_s} (#{response.body.to_json})"
71
+ else
72
+ response.body.send "to_#{@format}"
73
+ end
74
+ )
75
+ end
76
+ end
@@ -0,0 +1,156 @@
1
+ class Nagira < Sinatra::Base
2
+
3
+ ##
4
+ # Parse nagios files.
5
+ #
6
+ # Note: *.parse methods are monkey-patched here (if you have required
7
+ # 'lib/nagira' above) to set min parsing interval to avoid file paring
8
+ # on each HTTP request. File is parsed only if it was changed and if
9
+ # it was parsed more then 60 (default) seconds ago. See
10
+ # +lib/nagira/timed_parse.rb+ for mor more info.
11
+ #
12
+ # In development mode use files located under +./test/data+
13
+ # directory. This allows to do development on the host where Nagios is
14
+ # notinstalled. If you want to change this edit configuration in
15
+ # config/environment.rb file.
16
+ #
17
+ # See also comments in config/default.rb file regarding nagios_cfg,
18
+ # status_cfg, objects_cfg.
19
+ #
20
+ # @method parse_nagios_files
21
+ # @overload before("Parse Nagios files")
22
+ before do
23
+ Logger.log("BackgroundParser is not running", :warning) if
24
+ BackgroundParser.configured? && BackgroundParser.dead?
25
+
26
+ Parser.parse
27
+
28
+ @status = Parser.status['hosts']
29
+ @objects = Parser.objects
30
+
31
+ #
32
+ # Add plural keys to use ActiveResource with Nagira
33
+ #
34
+ @objects.keys.each do |singular|
35
+ @objects[singular.to_s.pluralize.to_sym] = @objects[singular]
36
+ end
37
+ end
38
+
39
+ ##
40
+ # @method clear_instance_data
41
+ # @overload before("clear data")
42
+ #
43
+ # Clear values onf instance variables before start.
44
+ #
45
+ before do
46
+ @data = []
47
+ @format = @output = nil
48
+ end
49
+
50
+ ##
51
+ # @method strip_extensions
52
+ # @overload before("detect format")
53
+ #
54
+ # Detect and strip output format extension
55
+ #
56
+ # Strip extension (@format) from HTTP route and set it as instance
57
+ # variable @format. Valid formats are .xml, .json, .yaml. If format
58
+ # is not specified, it is set to default format
59
+ # (Nagira.settings.format).
60
+ #
61
+ # \@format can be assigned one of the symbols: :xml, :json, :yaml.
62
+ #
63
+ # = Examples
64
+ #
65
+ # GET /_objects # => default format
66
+ # GET /_objects.json # => :json
67
+ # GET /_status/_list.yaml # => :yaml
68
+ #
69
+ before do
70
+ request.path_info.sub!(/#{settings.format_extensions}/, '')
71
+ @format = ($1 || settings.format).to_sym
72
+ content_type "application/#{@format.to_s}"
73
+ end
74
+
75
+ ##
76
+ # @method detect_ar_type
77
+ # @overload before('detect ActiveResource mode')
78
+ #
79
+ # Detect if this a request for ActiveResource PATH
80
+ #
81
+ before do
82
+ @active_resource = request.path_info =~ %r{^#{Nagira::AR_PREFIX}/}
83
+ end
84
+
85
+ ##
86
+ # @method strip_output_type
87
+ # @overload before('detect output mode')
88
+ #
89
+ # Detect output mode modifier
90
+ #
91
+ # Detect and strip output type from HTTP route. Full list of
92
+ # output types is +:list+, +:state+ or +:full+, corresponding to
93
+ # (+/list, +/state+, +/full+ routes).
94
+ #
95
+ # Output type defined by route modifier appended to the end of HTTP
96
+ # route. If no output type specfied it is set to +:full+. Output
97
+ # mode can be followed by format extension (+.json+, +.xml+ or
98
+ # +.yaml+).
99
+ #
100
+ # = Examples
101
+ #
102
+ # GET /_objects/_list # => :list
103
+ # GET /_status/_state # => :state
104
+ # GET /_status/:hostname # => :full
105
+ # GET /_status # => :normal
106
+ #
107
+ before do
108
+ request.path_info.sub!(/\/_(list|state|full)$/, '')
109
+ @output = ($1 || :normal).to_sym
110
+ end
111
+
112
+ ##
113
+ # @method find_jsonp_callback
114
+ # @overload before('find callback name')
115
+ #
116
+ # Detects if request is using jQuery JSON-P and sets @callback
117
+ # variable. @callback variable is used if after method and prepends
118
+ # JSON data with callback function name.
119
+ #
120
+ # = Example
121
+ #
122
+ # GET /_api?callback=jQuery12313123123 # @callback == jQuery12313123123
123
+ #
124
+ # JSONP support is based on the code from +sinatra/jsonp+ Gem
125
+ # https://github.com/shtirlic/sinatra-jsonp.
126
+ #
127
+ before do
128
+ if @format == :json
129
+ ['callback','jscallback','jsonp','jsoncallback'].each do |x|
130
+ @callback = params.delete(x) unless @callback
131
+ end
132
+ end
133
+ end
134
+
135
+ # @method parse_input_data
136
+ # @overload before("Parse PUT request body")
137
+ #
138
+ # Process the data before on each HTTP request.
139
+ #
140
+ # @return [Array] @input Sets @input instance variable.
141
+ #
142
+ before do
143
+ if request.put?
144
+ data = request.body.read
145
+ @input = case @format
146
+ when :json then JSON.parse data
147
+ when :xml then Hash.from_xml data
148
+ when :yaml then YAML.load data
149
+ end
150
+ # Make sure we always return an Array
151
+ @input = [@input] if @input.is_a? Hash
152
+ @input
153
+ end
154
+ end
155
+
156
+ end