nagira 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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