nagios_parser 1.0.0
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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +13 -0
- data/README.md +134 -0
- data/Rakefile +20 -0
- data/lib/nagios_parser/object/parser.rb +206 -0
- data/lib/nagios_parser/object/parser.y +91 -0
- data/lib/nagios_parser/status/parser.rb +244 -0
- data/lib/nagios_parser/status/parser.y +88 -0
- data/lib/nagios_parser/version.rb +3 -0
- data/lib/nagios_parser.rb +2 -0
- data/nagios_parser.gemspec +28 -0
- data/spec/nagios_parser/object/parser_spec.rb +91 -0
- data/spec/nagios_parser/status/parser_spec.rb +100 -0
- data/spec/spec_helper.rb +8 -0
- metadata +123 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (c) 2010 Bernd Ahlers <bernd@tuneafish.de>
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and distribute this software for any
|
4
|
+
purpose with or without fee is hereby granted, provided that the above
|
5
|
+
copyright notice and this permission notice appear in all copies.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
Nagios Parser
|
2
|
+
=============
|
3
|
+
|
4
|
+
# Description
|
5
|
+
|
6
|
+
The `nagios_parser` gem provides a parser for the Nagios `status.dat`
|
7
|
+
files and a parser for the Nagios object definition files.
|
8
|
+
|
9
|
+
* NagiosParser::Status::Parser
|
10
|
+
* NagiosParser::Object::Parser
|
11
|
+
|
12
|
+
Both parsers return plain hashes and arrays. There are no special
|
13
|
+
Nagios objects or something like that. That means you can create
|
14
|
+
your own wrapping objects or use the simple data structure
|
15
|
+
directly.
|
16
|
+
|
17
|
+
# Installation
|
18
|
+
|
19
|
+
# gem install nagios_parser
|
20
|
+
|
21
|
+
# Usage
|
22
|
+
|
23
|
+
## Status Parser
|
24
|
+
|
25
|
+
require 'nagios_parser/status/parser'
|
26
|
+
require 'pp'
|
27
|
+
|
28
|
+
status = <<-STATUS
|
29
|
+
info {
|
30
|
+
created=1291408262
|
31
|
+
version=3.2.0
|
32
|
+
last_update_check=1291201457
|
33
|
+
update_available=1
|
34
|
+
last_version=3.2.0
|
35
|
+
new_version=3.2.3
|
36
|
+
}
|
37
|
+
hoststatus {
|
38
|
+
host_name=server1
|
39
|
+
modified_attributes=0
|
40
|
+
check_command=check-ping
|
41
|
+
check_period=24x7
|
42
|
+
notification_period=24x7
|
43
|
+
check_interval=5.000000
|
44
|
+
retry_interval=1.000000
|
45
|
+
event_handler=
|
46
|
+
has_been_checked=1
|
47
|
+
}
|
48
|
+
STATUS
|
49
|
+
|
50
|
+
data = NagiosParser::Status::Parser.parse(status)
|
51
|
+
pp data
|
52
|
+
|
53
|
+
This will print a data structure that looks like this.
|
54
|
+
|
55
|
+
{"info"=>
|
56
|
+
[{"last_version"=>"3.2.0",
|
57
|
+
"version"=>"3.2.0",
|
58
|
+
"last_update_check"=>1291201457,
|
59
|
+
"new_version"=>"3.2.3",
|
60
|
+
"update_available"=>1,
|
61
|
+
"created"=>1291408262}],
|
62
|
+
"hoststatus"=>
|
63
|
+
[{"check_command"=>"check-ping",
|
64
|
+
"host_name"=>"server1",
|
65
|
+
"notification_period"=>"24x7",
|
66
|
+
"check_period"=>"24x7",
|
67
|
+
"modified_attributes"=>0,
|
68
|
+
"retry_interval"=>"1.000000",
|
69
|
+
"has_been_checked"=>1,
|
70
|
+
"event_handler"=>nil,
|
71
|
+
"check_interval"=>"5.000000"}]}
|
72
|
+
|
73
|
+
## Object Parser
|
74
|
+
|
75
|
+
require 'nagios_parser/object/parser'
|
76
|
+
require 'pp'
|
77
|
+
|
78
|
+
object = <<-OBJECT
|
79
|
+
define command {
|
80
|
+
command_name check-http
|
81
|
+
command_line $USER1$/check_http -I $HOSTADDRESS$ -w 420 -c 840
|
82
|
+
}
|
83
|
+
define host {
|
84
|
+
host_name server1
|
85
|
+
alias server1.example.com
|
86
|
+
address 10.0.0.1
|
87
|
+
}
|
88
|
+
OBJECT
|
89
|
+
|
90
|
+
data = NagiosParser::Object::Parser.parse(object)
|
91
|
+
pp data
|
92
|
+
|
93
|
+
This will print a data structure that looks like this.
|
94
|
+
|
95
|
+
{"command"=>
|
96
|
+
[{"command_name"=>"check-http",
|
97
|
+
"command_line"=>"$USER1$/check_http -I $HOSTADDRESS$ -w 420 -c 840"}],
|
98
|
+
"host"=>
|
99
|
+
[{"address"=>"10.0.0.1",
|
100
|
+
"host_name"=>"server1",
|
101
|
+
"alias"=>"server1.example.com"}]}
|
102
|
+
|
103
|
+
# Development
|
104
|
+
|
105
|
+
The parsers are based on the racc parser generator. racc is needed
|
106
|
+
at runtime, but that should be no problem since it's included in the
|
107
|
+
Ruby standard library.
|
108
|
+
|
109
|
+
To modify the parsers you have to modify the `.y` files and regenerate
|
110
|
+
the Ruby files afterwards. There are two rake tasks to help with that.
|
111
|
+
|
112
|
+
* `rake parser::status`
|
113
|
+
* `rake parser::object`
|
114
|
+
|
115
|
+
The bundler gem is used to handle the development dependencies.
|
116
|
+
Run `bundle install` to install them.
|
117
|
+
|
118
|
+
Please let me know if you have any questions or if you run into any
|
119
|
+
problems.
|
120
|
+
|
121
|
+
# Contribute
|
122
|
+
|
123
|
+
* Fork the project.
|
124
|
+
* Make your feature addition or bug fix.
|
125
|
+
* Add tests for it. This is important so I don't break it in a
|
126
|
+
future version unintentionally.
|
127
|
+
* Commit, do not mess with Rakefile, version, or history.
|
128
|
+
(if you want to have your own version, that is fine but bump version
|
129
|
+
in a commit by itself I can ignore when I pull)
|
130
|
+
* Send me a pull request. Bonus points for topic branches.
|
131
|
+
|
132
|
+
# Copyright
|
133
|
+
|
134
|
+
Copyright (c) 2010 Bernd Ahlers. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new do |t|
|
7
|
+
t.rcov = false
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :parser do
|
11
|
+
desc 'Generate the status parser with racc'
|
12
|
+
task :status => [ 'lib/nagios_parser/status/parser.rb' ]
|
13
|
+
|
14
|
+
desc 'Generate the object parser with racc'
|
15
|
+
task :object => [ 'lib/nagios_parser/object/parser.rb' ]
|
16
|
+
|
17
|
+
rule '.rb' => '.y' do |target|
|
18
|
+
sh "racc -o #{target.name} #{target.source}"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
#
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by Racc 1.4.6
|
4
|
+
# from Racc grammer file "".
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'racc/parser.rb'
|
8
|
+
|
9
|
+
require 'strscan'
|
10
|
+
|
11
|
+
module NagiosParser
|
12
|
+
module Object
|
13
|
+
class Parser < Racc::Parser
|
14
|
+
|
15
|
+
module_eval(<<'...end parser.y/module_eval...', 'parser.y', 34)
|
16
|
+
|
17
|
+
private
|
18
|
+
def last_is_key?(list)
|
19
|
+
list.last[0] == :KEY
|
20
|
+
end
|
21
|
+
|
22
|
+
public
|
23
|
+
def create_token(string)
|
24
|
+
result = []
|
25
|
+
inside = false
|
26
|
+
scanner = StringScanner.new(string)
|
27
|
+
|
28
|
+
until scanner.empty?
|
29
|
+
case
|
30
|
+
when scanner.scan(/\s+/)
|
31
|
+
# ignore whitespace
|
32
|
+
when scanner.scan(/#[^\n]*/)
|
33
|
+
# ignore comments
|
34
|
+
when scanner.scan(/define/)
|
35
|
+
result << [:DEFINE, nil]
|
36
|
+
when (!inside and match = scanner.scan(/\w+/))
|
37
|
+
result << [:TYPE, match]
|
38
|
+
when match = scanner.scan(/\{/)
|
39
|
+
inside = true
|
40
|
+
result << [:OPEN, nil]
|
41
|
+
when match = scanner.scan(/\}/)
|
42
|
+
inside = false
|
43
|
+
result << [:CLOSE, nil]
|
44
|
+
when (!last_is_key?(result) and match = scanner.scan(/\w+/))
|
45
|
+
result << [:KEY, match.chomp.gsub(/\s+$/, '')]
|
46
|
+
when (inside and match = scanner.scan(/\d+$/))
|
47
|
+
result << [:VALUE, match.to_i]
|
48
|
+
when (inside and match = scanner.scan(/[^\n\}]+/))
|
49
|
+
result << [:VALUE, match.gsub(/\s+$/, '')]
|
50
|
+
else
|
51
|
+
raise "Can't tokenize <#{scanner.peek(10)}>"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
result << [false, false]
|
56
|
+
end
|
57
|
+
|
58
|
+
attr_accessor :token
|
59
|
+
|
60
|
+
def self.parse(string)
|
61
|
+
new.parse(string)
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(string)
|
65
|
+
@result = {}
|
66
|
+
@token = create_token(string)
|
67
|
+
do_parse
|
68
|
+
@result
|
69
|
+
end
|
70
|
+
|
71
|
+
def next_token
|
72
|
+
@token.shift
|
73
|
+
end
|
74
|
+
...end parser.y/module_eval...
|
75
|
+
##### State transition tables begin ###
|
76
|
+
|
77
|
+
racc_action_table = [
|
78
|
+
5, 8, 1, 13, 11, 7, 1, 11, 4, 14 ]
|
79
|
+
|
80
|
+
racc_action_check = [
|
81
|
+
2, 5, 2, 9, 9, 4, 0, 7, 1, 11 ]
|
82
|
+
|
83
|
+
racc_action_pointer = [
|
84
|
+
4, 5, 0, nil, 1, 1, nil, 1, nil, -2,
|
85
|
+
nil, 2, nil, nil, nil ]
|
86
|
+
|
87
|
+
racc_action_default = [
|
88
|
+
-7, -7, -7, -1, -7, -7, -2, -7, 15, -7,
|
89
|
+
-4, -7, -5, -3, -6 ]
|
90
|
+
|
91
|
+
racc_goto_table = [
|
92
|
+
10, 3, 12, 6, 9, 2 ]
|
93
|
+
|
94
|
+
racc_goto_check = [
|
95
|
+
4, 2, 4, 2, 3, 1 ]
|
96
|
+
|
97
|
+
racc_goto_pointer = [
|
98
|
+
nil, 5, 1, -3, -7 ]
|
99
|
+
|
100
|
+
racc_goto_default = [
|
101
|
+
nil, nil, nil, nil, nil ]
|
102
|
+
|
103
|
+
racc_reduce_table = [
|
104
|
+
0, 0, :racc_error,
|
105
|
+
1, 9, :_reduce_none,
|
106
|
+
2, 9, :_reduce_none,
|
107
|
+
5, 10, :_reduce_3,
|
108
|
+
1, 11, :_reduce_none,
|
109
|
+
2, 11, :_reduce_5,
|
110
|
+
2, 12, :_reduce_6 ]
|
111
|
+
|
112
|
+
racc_reduce_n = 7
|
113
|
+
|
114
|
+
racc_shift_n = 15
|
115
|
+
|
116
|
+
racc_token_table = {
|
117
|
+
false => 0,
|
118
|
+
:error => 1,
|
119
|
+
:DEFINE => 2,
|
120
|
+
:TYPE => 3,
|
121
|
+
:OPEN => 4,
|
122
|
+
:CLOSE => 5,
|
123
|
+
:KEY => 6,
|
124
|
+
:VALUE => 7 }
|
125
|
+
|
126
|
+
racc_nt_base = 8
|
127
|
+
|
128
|
+
racc_use_result_var = true
|
129
|
+
|
130
|
+
Racc_arg = [
|
131
|
+
racc_action_table,
|
132
|
+
racc_action_check,
|
133
|
+
racc_action_default,
|
134
|
+
racc_action_pointer,
|
135
|
+
racc_goto_table,
|
136
|
+
racc_goto_check,
|
137
|
+
racc_goto_default,
|
138
|
+
racc_goto_pointer,
|
139
|
+
racc_nt_base,
|
140
|
+
racc_reduce_table,
|
141
|
+
racc_token_table,
|
142
|
+
racc_shift_n,
|
143
|
+
racc_reduce_n,
|
144
|
+
racc_use_result_var ]
|
145
|
+
|
146
|
+
Racc_token_to_s_table = [
|
147
|
+
"$end",
|
148
|
+
"error",
|
149
|
+
"DEFINE",
|
150
|
+
"TYPE",
|
151
|
+
"OPEN",
|
152
|
+
"CLOSE",
|
153
|
+
"KEY",
|
154
|
+
"VALUE",
|
155
|
+
"$start",
|
156
|
+
"defines",
|
157
|
+
"define",
|
158
|
+
"assignments",
|
159
|
+
"assignment" ]
|
160
|
+
|
161
|
+
Racc_debug_parser = false
|
162
|
+
|
163
|
+
##### State transition tables end #####
|
164
|
+
|
165
|
+
# reduce 0 omitted
|
166
|
+
|
167
|
+
# reduce 1 omitted
|
168
|
+
|
169
|
+
# reduce 2 omitted
|
170
|
+
|
171
|
+
module_eval(<<'.,.,', 'parser.y', 11)
|
172
|
+
def _reduce_3(val, _values, result)
|
173
|
+
@result[val[1]] ||= []
|
174
|
+
@result[val[1]] << val[3]
|
175
|
+
|
176
|
+
result
|
177
|
+
end
|
178
|
+
.,.,
|
179
|
+
|
180
|
+
# reduce 4 omitted
|
181
|
+
|
182
|
+
module_eval(<<'.,.,', 'parser.y', 18)
|
183
|
+
def _reduce_5(val, _values, result)
|
184
|
+
val[1].each do |key, value|
|
185
|
+
val[0][key] = value
|
186
|
+
end
|
187
|
+
result = val[0]
|
188
|
+
|
189
|
+
result
|
190
|
+
end
|
191
|
+
.,.,
|
192
|
+
|
193
|
+
module_eval(<<'.,.,', 'parser.y', 25)
|
194
|
+
def _reduce_6(val, _values, result)
|
195
|
+
result = {val[0] => val[1]}
|
196
|
+
result
|
197
|
+
end
|
198
|
+
.,.,
|
199
|
+
|
200
|
+
def _reduce_none(val, _values, result)
|
201
|
+
val[0]
|
202
|
+
end
|
203
|
+
|
204
|
+
end # class Parser
|
205
|
+
end # module Object
|
206
|
+
end # module NagiosParser
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class NagiosParser::Object::Parser
|
2
|
+
token
|
3
|
+
DEFINE TYPE OPEN CLOSE KEY VALUE
|
4
|
+
|
5
|
+
rule
|
6
|
+
defines
|
7
|
+
: define
|
8
|
+
| defines define
|
9
|
+
;
|
10
|
+
define
|
11
|
+
: DEFINE TYPE OPEN assignments CLOSE {
|
12
|
+
@result[val[1]] ||= []
|
13
|
+
@result[val[1]] << val[3]
|
14
|
+
}
|
15
|
+
;
|
16
|
+
assignments
|
17
|
+
: assignment
|
18
|
+
| assignments assignment {
|
19
|
+
val[1].each do |key, value|
|
20
|
+
val[0][key] = value
|
21
|
+
end
|
22
|
+
result = val[0]
|
23
|
+
}
|
24
|
+
;
|
25
|
+
assignment
|
26
|
+
: KEY VALUE { result = {val[0] => val[1]} }
|
27
|
+
;
|
28
|
+
end
|
29
|
+
|
30
|
+
---- header
|
31
|
+
require 'strscan'
|
32
|
+
|
33
|
+
---- inner
|
34
|
+
|
35
|
+
private
|
36
|
+
def last_is_key?(list)
|
37
|
+
list.last[0] == :KEY
|
38
|
+
end
|
39
|
+
|
40
|
+
public
|
41
|
+
def create_token(string)
|
42
|
+
result = []
|
43
|
+
inside = false
|
44
|
+
scanner = StringScanner.new(string)
|
45
|
+
|
46
|
+
until scanner.empty?
|
47
|
+
case
|
48
|
+
when scanner.scan(/\s+/)
|
49
|
+
# ignore whitespace
|
50
|
+
when scanner.scan(/#[^\n]*/)
|
51
|
+
# ignore comments
|
52
|
+
when scanner.scan(/define/)
|
53
|
+
result << [:DEFINE, nil]
|
54
|
+
when (!inside and match = scanner.scan(/\w+/))
|
55
|
+
result << [:TYPE, match]
|
56
|
+
when match = scanner.scan(/\{/)
|
57
|
+
inside = true
|
58
|
+
result << [:OPEN, nil]
|
59
|
+
when match = scanner.scan(/\}/)
|
60
|
+
inside = false
|
61
|
+
result << [:CLOSE, nil]
|
62
|
+
when (!last_is_key?(result) and match = scanner.scan(/\w+/))
|
63
|
+
result << [:KEY, match.chomp.gsub(/\s+$/, '')]
|
64
|
+
when (inside and match = scanner.scan(/\d+$/))
|
65
|
+
result << [:VALUE, match.to_i]
|
66
|
+
when (inside and match = scanner.scan(/[^\n\}]+/))
|
67
|
+
result << [:VALUE, match.gsub(/\s+$/, '')]
|
68
|
+
else
|
69
|
+
raise "Can't tokenize <#{scanner.peek(10)}>"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
result << [false, false]
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_accessor :token
|
77
|
+
|
78
|
+
def self.parse(string)
|
79
|
+
new.parse(string)
|
80
|
+
end
|
81
|
+
|
82
|
+
def parse(string)
|
83
|
+
@result = {}
|
84
|
+
@token = create_token(string)
|
85
|
+
do_parse
|
86
|
+
@result
|
87
|
+
end
|
88
|
+
|
89
|
+
def next_token
|
90
|
+
@token.shift
|
91
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
#
|
2
|
+
# DO NOT MODIFY!!!!
|
3
|
+
# This file is automatically generated by Racc 1.4.6
|
4
|
+
# from Racc grammer file "".
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'racc/parser.rb'
|
8
|
+
|
9
|
+
require 'strscan'
|
10
|
+
|
11
|
+
module NagiosParser
|
12
|
+
module Status
|
13
|
+
class Parser < Racc::Parser
|
14
|
+
|
15
|
+
module_eval(<<'...end parser.y/module_eval...', 'parser.y', 39)
|
16
|
+
|
17
|
+
def create_token(string)
|
18
|
+
result = []
|
19
|
+
inside = false
|
20
|
+
scanner = StringScanner.new(string)
|
21
|
+
|
22
|
+
until scanner.empty?
|
23
|
+
case
|
24
|
+
when scanner.scan(/\s+/)
|
25
|
+
# ignore whitespace
|
26
|
+
when scanner.scan(/#[^\n]*/)
|
27
|
+
# ignore comments
|
28
|
+
when (!inside and match = scanner.scan(/\w+/))
|
29
|
+
result << [match, match]
|
30
|
+
when match = scanner.scan(/\{/)
|
31
|
+
inside = true
|
32
|
+
result << [:OPEN, nil]
|
33
|
+
when match = scanner.scan(/\}/)
|
34
|
+
inside = false
|
35
|
+
result << [:CLOSE, nil]
|
36
|
+
when match = scanner.scan(/\w+\s*\=/)
|
37
|
+
result << [:KEY, match.chop.gsub(/\s+$/, '')]
|
38
|
+
when (inside and match = scanner.scan(/\d+$/))
|
39
|
+
result << [:VALUE, match.to_i]
|
40
|
+
when (inside and match = scanner.scan(/[^\n\}]+/))
|
41
|
+
result << [:VALUE, match.gsub(/\s+$/, '')]
|
42
|
+
else
|
43
|
+
raise "Can't tokenize <#{scanner.peek(10)}>"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
result << [false, false]
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_accessor :token
|
51
|
+
|
52
|
+
def self.parse(string)
|
53
|
+
new.parse(string)
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse(string)
|
57
|
+
@result = {}
|
58
|
+
@token = create_token(string)
|
59
|
+
do_parse
|
60
|
+
@result
|
61
|
+
end
|
62
|
+
|
63
|
+
def next_token
|
64
|
+
@token.shift
|
65
|
+
end
|
66
|
+
...end parser.y/module_eval...
|
67
|
+
##### State transition tables begin ###
|
68
|
+
|
69
|
+
racc_action_table = [
|
70
|
+
11, 19, 15, 13, 15, 18, 6, 7, 8, 9,
|
71
|
+
10, 1, 2, 6, 7, 8, 9, 10, 1, 2,
|
72
|
+
14 ]
|
73
|
+
|
74
|
+
racc_action_check = [
|
75
|
+
3, 16, 16, 5, 13, 15, 3, 3, 3, 3,
|
76
|
+
3, 3, 3, 0, 0, 0, 0, 0, 0, 0,
|
77
|
+
11 ]
|
78
|
+
|
79
|
+
racc_action_pointer = [
|
80
|
+
7, nil, nil, 0, nil, 1, nil, nil, nil, nil,
|
81
|
+
nil, 20, nil, 0, nil, 0, -2, nil, nil, nil,
|
82
|
+
nil ]
|
83
|
+
|
84
|
+
racc_action_default = [
|
85
|
+
-15, -9, -10, -15, -1, -15, -4, -5, -6, -7,
|
86
|
+
-8, -15, -2, -15, 21, -13, -15, -11, -14, -3,
|
87
|
+
-12 ]
|
88
|
+
|
89
|
+
racc_goto_table = [
|
90
|
+
17, 4, 16, 20, 12, 3 ]
|
91
|
+
|
92
|
+
racc_goto_check = [
|
93
|
+
5, 2, 4, 5, 2, 1 ]
|
94
|
+
|
95
|
+
racc_goto_pointer = [
|
96
|
+
nil, 5, 1, nil, -11, -13 ]
|
97
|
+
|
98
|
+
racc_goto_default = [
|
99
|
+
nil, nil, nil, 5, nil, nil ]
|
100
|
+
|
101
|
+
racc_reduce_table = [
|
102
|
+
0, 0, :racc_error,
|
103
|
+
1, 14, :_reduce_none,
|
104
|
+
2, 14, :_reduce_none,
|
105
|
+
4, 15, :_reduce_3,
|
106
|
+
1, 16, :_reduce_none,
|
107
|
+
1, 16, :_reduce_none,
|
108
|
+
1, 16, :_reduce_none,
|
109
|
+
1, 16, :_reduce_none,
|
110
|
+
1, 16, :_reduce_none,
|
111
|
+
1, 16, :_reduce_none,
|
112
|
+
1, 16, :_reduce_none,
|
113
|
+
1, 17, :_reduce_none,
|
114
|
+
2, 17, :_reduce_12,
|
115
|
+
1, 18, :_reduce_13,
|
116
|
+
2, 18, :_reduce_14 ]
|
117
|
+
|
118
|
+
racc_reduce_n = 15
|
119
|
+
|
120
|
+
racc_shift_n = 21
|
121
|
+
|
122
|
+
racc_token_table = {
|
123
|
+
false => 0,
|
124
|
+
:error => 1,
|
125
|
+
:OPEN => 2,
|
126
|
+
:CLOSE => 3,
|
127
|
+
:KEY => 4,
|
128
|
+
:VALUE => 5,
|
129
|
+
"hostcomment" => 6,
|
130
|
+
"servicestatus" => 7,
|
131
|
+
"info" => 8,
|
132
|
+
"programstatus" => 9,
|
133
|
+
"hoststatus" => 10,
|
134
|
+
"contactstatus" => 11,
|
135
|
+
"servicecomment" => 12 }
|
136
|
+
|
137
|
+
racc_nt_base = 13
|
138
|
+
|
139
|
+
racc_use_result_var = true
|
140
|
+
|
141
|
+
Racc_arg = [
|
142
|
+
racc_action_table,
|
143
|
+
racc_action_check,
|
144
|
+
racc_action_default,
|
145
|
+
racc_action_pointer,
|
146
|
+
racc_goto_table,
|
147
|
+
racc_goto_check,
|
148
|
+
racc_goto_default,
|
149
|
+
racc_goto_pointer,
|
150
|
+
racc_nt_base,
|
151
|
+
racc_reduce_table,
|
152
|
+
racc_token_table,
|
153
|
+
racc_shift_n,
|
154
|
+
racc_reduce_n,
|
155
|
+
racc_use_result_var ]
|
156
|
+
|
157
|
+
Racc_token_to_s_table = [
|
158
|
+
"$end",
|
159
|
+
"error",
|
160
|
+
"OPEN",
|
161
|
+
"CLOSE",
|
162
|
+
"KEY",
|
163
|
+
"VALUE",
|
164
|
+
"\"hostcomment\"",
|
165
|
+
"\"servicestatus\"",
|
166
|
+
"\"info\"",
|
167
|
+
"\"programstatus\"",
|
168
|
+
"\"hoststatus\"",
|
169
|
+
"\"contactstatus\"",
|
170
|
+
"\"servicecomment\"",
|
171
|
+
"$start",
|
172
|
+
"types",
|
173
|
+
"type",
|
174
|
+
"type_names",
|
175
|
+
"assignments",
|
176
|
+
"assignment" ]
|
177
|
+
|
178
|
+
Racc_debug_parser = false
|
179
|
+
|
180
|
+
##### State transition tables end #####
|
181
|
+
|
182
|
+
# reduce 0 omitted
|
183
|
+
|
184
|
+
# reduce 1 omitted
|
185
|
+
|
186
|
+
# reduce 2 omitted
|
187
|
+
|
188
|
+
module_eval(<<'.,.,', 'parser.y', 11)
|
189
|
+
def _reduce_3(val, _values, result)
|
190
|
+
@result[val[0]] ||= []
|
191
|
+
@result[val[0]] << val[2]
|
192
|
+
|
193
|
+
result
|
194
|
+
end
|
195
|
+
.,.,
|
196
|
+
|
197
|
+
# reduce 4 omitted
|
198
|
+
|
199
|
+
# reduce 5 omitted
|
200
|
+
|
201
|
+
# reduce 6 omitted
|
202
|
+
|
203
|
+
# reduce 7 omitted
|
204
|
+
|
205
|
+
# reduce 8 omitted
|
206
|
+
|
207
|
+
# reduce 9 omitted
|
208
|
+
|
209
|
+
# reduce 10 omitted
|
210
|
+
|
211
|
+
# reduce 11 omitted
|
212
|
+
|
213
|
+
module_eval(<<'.,.,', 'parser.y', 22)
|
214
|
+
def _reduce_12(val, _values, result)
|
215
|
+
val[1].each do |key, value|
|
216
|
+
val[0][key] = value
|
217
|
+
end
|
218
|
+
result = val[0]
|
219
|
+
|
220
|
+
result
|
221
|
+
end
|
222
|
+
.,.,
|
223
|
+
|
224
|
+
module_eval(<<'.,.,', 'parser.y', 29)
|
225
|
+
def _reduce_13(val, _values, result)
|
226
|
+
result = {val[0] => nil}
|
227
|
+
result
|
228
|
+
end
|
229
|
+
.,.,
|
230
|
+
|
231
|
+
module_eval(<<'.,.,', 'parser.y', 30)
|
232
|
+
def _reduce_14(val, _values, result)
|
233
|
+
result = {val[0] => val[1]}
|
234
|
+
result
|
235
|
+
end
|
236
|
+
.,.,
|
237
|
+
|
238
|
+
def _reduce_none(val, _values, result)
|
239
|
+
val[0]
|
240
|
+
end
|
241
|
+
|
242
|
+
end # class Parser
|
243
|
+
end # module Status
|
244
|
+
end # module NagiosParser
|
@@ -0,0 +1,88 @@
|
|
1
|
+
class NagiosParser::Status::Parser
|
2
|
+
token
|
3
|
+
OPEN CLOSE KEY VALUE
|
4
|
+
|
5
|
+
rule
|
6
|
+
types
|
7
|
+
: type
|
8
|
+
| types type
|
9
|
+
;
|
10
|
+
type
|
11
|
+
: type_names OPEN assignments CLOSE {
|
12
|
+
@result[val[0]] ||= []
|
13
|
+
@result[val[0]] << val[2]
|
14
|
+
}
|
15
|
+
;
|
16
|
+
type_names
|
17
|
+
: 'hostcomment' | 'servicestatus' | 'info' | 'programstatus'
|
18
|
+
| 'hoststatus' | 'contactstatus' | 'servicecomment'
|
19
|
+
;
|
20
|
+
assignments
|
21
|
+
: assignment
|
22
|
+
| assignments assignment {
|
23
|
+
val[1].each do |key, value|
|
24
|
+
val[0][key] = value
|
25
|
+
end
|
26
|
+
result = val[0]
|
27
|
+
}
|
28
|
+
;
|
29
|
+
assignment
|
30
|
+
: KEY { result = {val[0] => nil}}
|
31
|
+
| KEY VALUE { result = {val[0] => val[1]} }
|
32
|
+
;
|
33
|
+
end
|
34
|
+
|
35
|
+
---- header
|
36
|
+
require 'strscan'
|
37
|
+
|
38
|
+
---- inner
|
39
|
+
|
40
|
+
def create_token(string)
|
41
|
+
result = []
|
42
|
+
inside = false
|
43
|
+
scanner = StringScanner.new(string)
|
44
|
+
|
45
|
+
until scanner.empty?
|
46
|
+
case
|
47
|
+
when scanner.scan(/\s+/)
|
48
|
+
# ignore whitespace
|
49
|
+
when scanner.scan(/#[^\n]*/)
|
50
|
+
# ignore comments
|
51
|
+
when (!inside and match = scanner.scan(/\w+/))
|
52
|
+
result << [match, match]
|
53
|
+
when match = scanner.scan(/\{/)
|
54
|
+
inside = true
|
55
|
+
result << [:OPEN, nil]
|
56
|
+
when match = scanner.scan(/\}/)
|
57
|
+
inside = false
|
58
|
+
result << [:CLOSE, nil]
|
59
|
+
when match = scanner.scan(/\w+\s*\=/)
|
60
|
+
result << [:KEY, match.chop.gsub(/\s+$/, '')]
|
61
|
+
when (inside and match = scanner.scan(/\d+$/))
|
62
|
+
result << [:VALUE, match.to_i]
|
63
|
+
when (inside and match = scanner.scan(/[^\n\}]+/))
|
64
|
+
result << [:VALUE, match.gsub(/\s+$/, '')]
|
65
|
+
else
|
66
|
+
raise "Can't tokenize <#{scanner.peek(10)}>"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
result << [false, false]
|
71
|
+
end
|
72
|
+
|
73
|
+
attr_accessor :token
|
74
|
+
|
75
|
+
def self.parse(string)
|
76
|
+
new.parse(string)
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse(string)
|
80
|
+
@result = {}
|
81
|
+
@token = create_token(string)
|
82
|
+
do_parse
|
83
|
+
@result
|
84
|
+
end
|
85
|
+
|
86
|
+
def next_token
|
87
|
+
@token.shift
|
88
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "nagios_parser/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "nagios_parser"
|
7
|
+
s.version = NagiosParser::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Bernd Ahlers"]
|
10
|
+
s.email = ["bernd@tuneafish.de"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/nagios_parser"
|
12
|
+
s.summary = %q{parser lib for parsing Nagios status and config files}
|
13
|
+
s.description = %q{
|
14
|
+
The nagios_parser gem provides parsers for Nagios config
|
15
|
+
and status files.
|
16
|
+
}
|
17
|
+
|
18
|
+
#s.rubyforge_project = "nagios_parser"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
|
25
|
+
s.add_development_dependency "rake"
|
26
|
+
s.add_development_dependency "racc"
|
27
|
+
s.add_development_dependency "rspec"
|
28
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nagios_parser/object/parser'
|
3
|
+
|
4
|
+
describe NagiosParser::Object::Parser do
|
5
|
+
let(:parser) { NagiosParser::Object::Parser.new }
|
6
|
+
|
7
|
+
describe ".parse" do
|
8
|
+
it "returns a hash of status types" do
|
9
|
+
data = parser.parse('define host { host_name foo }')
|
10
|
+
data['host'].first['host_name'].should == 'foo'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#create_token" do
|
15
|
+
context "given a valid string" do
|
16
|
+
it "creates a valid token list" do
|
17
|
+
string = <<-RUBY
|
18
|
+
define host {
|
19
|
+
host_name foo.example.com
|
20
|
+
_plugin_path /usr/lib64/nagios/plugins
|
21
|
+
}
|
22
|
+
define service {
|
23
|
+
host_name foo.example.com
|
24
|
+
service_description SUPERD
|
25
|
+
}
|
26
|
+
RUBY
|
27
|
+
|
28
|
+
parser.create_token(string).should == [
|
29
|
+
[:DEFINE, nil],
|
30
|
+
[:TYPE, 'host'],
|
31
|
+
[:OPEN, nil],
|
32
|
+
[:KEY, 'host_name'],
|
33
|
+
[:VALUE, 'foo.example.com'],
|
34
|
+
[:KEY, '_plugin_path'],
|
35
|
+
[:VALUE, '/usr/lib64/nagios/plugins'],
|
36
|
+
[:CLOSE, nil],
|
37
|
+
[:DEFINE, nil],
|
38
|
+
[:TYPE, 'service'],
|
39
|
+
[:OPEN, nil],
|
40
|
+
[:KEY, 'host_name'],
|
41
|
+
[:VALUE, 'foo.example.com'],
|
42
|
+
[:KEY, 'service_description'],
|
43
|
+
[:VALUE, 'SUPERD'],
|
44
|
+
[:CLOSE, nil],
|
45
|
+
[false, false]
|
46
|
+
]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#next_token" do
|
52
|
+
it "returns shifts the next element off the token list" do
|
53
|
+
parser.token = [:one, :two, :three]
|
54
|
+
parser.next_token
|
55
|
+
parser.next_token.should == :two
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#parse" do
|
60
|
+
context "with a valid string" do
|
61
|
+
it "returns a hash of status types" do
|
62
|
+
string = <<-RUBY
|
63
|
+
define host {
|
64
|
+
host_name foo.example.com
|
65
|
+
notification_interval 40
|
66
|
+
}
|
67
|
+
RUBY
|
68
|
+
|
69
|
+
data = parser.parse(string)
|
70
|
+
data['host'].first['host_name'] == 'foo.example.com'
|
71
|
+
data['host'].first['notification_interval'] == 40
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "with an invalid status type" do
|
76
|
+
it "will raise an exception" do
|
77
|
+
expect {
|
78
|
+
parser.parse('FooBar { info test }')
|
79
|
+
}.to raise_error
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with invalid status data" do
|
84
|
+
it "will raise an exception" do
|
85
|
+
expect {
|
86
|
+
parser.parse('define host { =test }')
|
87
|
+
}.to raise_error
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'nagios_parser/status/parser'
|
3
|
+
|
4
|
+
describe NagiosParser::Status::Parser do
|
5
|
+
let(:parser) { NagiosParser::Status::Parser.new }
|
6
|
+
|
7
|
+
describe ".parse" do
|
8
|
+
it "returns a hash of status types" do
|
9
|
+
data = parser.parse('info { version=3.2.0 }')
|
10
|
+
data['info'].first['version'].should == '3.2.0'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#create_token" do
|
15
|
+
context "given a valid string" do
|
16
|
+
it "creates a valid token list" do
|
17
|
+
string = <<-RUBY
|
18
|
+
hoststatus {
|
19
|
+
bar=baz
|
20
|
+
hello = world
|
21
|
+
foo= bar
|
22
|
+
foo = bar baz hello world
|
23
|
+
eek = 1
|
24
|
+
}
|
25
|
+
info { version=3.2.0 }
|
26
|
+
|
27
|
+
programstatus {
|
28
|
+
last_command_check=1291408262
|
29
|
+
global_service_event_handler=
|
30
|
+
}
|
31
|
+
RUBY
|
32
|
+
|
33
|
+
parser.create_token(string).should == [
|
34
|
+
['hoststatus', 'hoststatus'],
|
35
|
+
[:OPEN, nil],
|
36
|
+
[:KEY, 'bar'], [:VALUE, 'baz'],
|
37
|
+
[:KEY, 'hello'], [:VALUE, 'world'],
|
38
|
+
[:KEY, 'foo'], [:VALUE, 'bar'],
|
39
|
+
[:KEY, 'foo'], [:VALUE, 'bar baz hello world'],
|
40
|
+
[:KEY, 'eek'], [:VALUE, 1],
|
41
|
+
[:CLOSE, nil],
|
42
|
+
['info', 'info'],
|
43
|
+
[:OPEN, nil],
|
44
|
+
[:KEY, 'version'], [:VALUE, '3.2.0'],
|
45
|
+
[:CLOSE, nil],
|
46
|
+
['programstatus', 'programstatus'],
|
47
|
+
[:OPEN, nil],
|
48
|
+
[:KEY, 'last_command_check'], [:VALUE, 1291408262],
|
49
|
+
[:KEY, 'global_service_event_handler'],
|
50
|
+
[:CLOSE, nil],
|
51
|
+
[false, false]
|
52
|
+
]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#next_token" do
|
58
|
+
it "returns shifts the next element off the token list" do
|
59
|
+
parser.token = [:one, :two, :three]
|
60
|
+
parser.next_token
|
61
|
+
parser.next_token.should == :two
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#parse" do
|
66
|
+
context "with a valid string" do
|
67
|
+
it "returns a hash of status types" do
|
68
|
+
string = <<-RUBY
|
69
|
+
hoststatus {
|
70
|
+
bar=baz
|
71
|
+
hello = world
|
72
|
+
version = 1
|
73
|
+
}
|
74
|
+
info { version=3.2.0 }
|
75
|
+
RUBY
|
76
|
+
|
77
|
+
data = parser.parse(string)
|
78
|
+
data['info'].first['version'].should == '3.2.0'
|
79
|
+
data['hoststatus'].first['bar'].should == 'baz'
|
80
|
+
data['hoststatus'].first['version'].should == 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with an invalid status type" do
|
85
|
+
it "will raise an exception" do
|
86
|
+
expect {
|
87
|
+
parser.parse('FooBar { info=test }')
|
88
|
+
}.to raise_error
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with invalid status data" do
|
93
|
+
it "will raise an exception" do
|
94
|
+
expect {
|
95
|
+
parser.parse('info { =test }')
|
96
|
+
}.to raise_error
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nagios_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Bernd Ahlers
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-12-16 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: racc
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
description: "\n The nagios_parser gem provides parsers for Nagios config\n and status files.\n "
|
64
|
+
email:
|
65
|
+
- bernd@tuneafish.de
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- .gitignore
|
74
|
+
- Gemfile
|
75
|
+
- LICENSE
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/nagios_parser.rb
|
79
|
+
- lib/nagios_parser/object/parser.rb
|
80
|
+
- lib/nagios_parser/object/parser.y
|
81
|
+
- lib/nagios_parser/status/parser.rb
|
82
|
+
- lib/nagios_parser/status/parser.y
|
83
|
+
- lib/nagios_parser/version.rb
|
84
|
+
- nagios_parser.gemspec
|
85
|
+
- spec/nagios_parser/object/parser_spec.rb
|
86
|
+
- spec/nagios_parser/status/parser_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
has_rdoc: true
|
89
|
+
homepage: http://rubygems.org/gems/nagios_parser
|
90
|
+
licenses: []
|
91
|
+
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
version: "0"
|
115
|
+
requirements: []
|
116
|
+
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.3.7
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: parser lib for parsing Nagios status and config files
|
122
|
+
test_files: []
|
123
|
+
|