nagios_config 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,39 @@
1
+ = NagiosConfig
2
+
3
+ NagiosConfig provides tools to parse, manipulate, generate and output Nagios configuration files using Ruby.
4
+
5
+ == NagiosConfig::Parser
6
+
7
+ NagiosConfig::Parser will parse both the object and main style Nagios configuration files, and has both a streaming API and the ability to produce a AST/DOM-like structure.
8
+
9
+ == NagiosConfig::Builder
10
+
11
+ NagiosConfig::Builder is a simple DSL for generating Nagios config files using Ruby
12
+
13
+ == NagiosConfig::Formater
14
+
15
+ NagiosConfig::Formater will take the data structures produced by the parser and builder and output them in the format of a Nagios config file.
16
+
17
+ == Making changes to a config file
18
+
19
+ Say for example you decided you want all your host names uppercase
20
+
21
+ require 'rubygems'
22
+ require 'nagios_config'
23
+
24
+ host_config = nil
25
+ File.open("hosts.cfg") do |f|
26
+ host_config = NagiosConfig::Parser.new.parse(f)
27
+ end
28
+
29
+ host_config.defines do |node|
30
+ if node.type.value == "host"
31
+ variable = node.variables.find {|node| node.name.value == "hostname"}
32
+ variable.val.value.upcase! if variable
33
+ end
34
+ end
35
+
36
+ File.open("hosts.cfg", "w") do |f|
37
+ NagiosConfig::Formatter.new(f).format(host_config)
38
+ end
39
+
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/nagios_config/errors"
2
+ require File.dirname(__FILE__) + "/nagios_config/node"
3
+ require File.dirname(__FILE__) + "/nagios_config/ast"
4
+ require File.dirname(__FILE__) + "/nagios_config/parser"
5
+ require File.dirname(__FILE__) + "/nagios_config/formater"
6
+ require File.dirname(__FILE__) + "/nagios_config/builder"
7
+ require File.dirname(__FILE__) + "/nagios_config/object"
@@ -0,0 +1,42 @@
1
+ module NagiosConfig
2
+
3
+ class TrailingComment < Node
4
+ end
5
+
6
+ class Whitespace < Node
7
+ node :trailing_comment, NagiosConfig::TrailingComment
8
+ end
9
+
10
+ class Comment < Node
11
+ end
12
+
13
+ class Type < Node
14
+ end
15
+
16
+ class Name < Node
17
+ end
18
+
19
+ class Value < Node
20
+ end
21
+
22
+ class Variable < Node
23
+ node :name, NagiosConfig::Name
24
+ node :val, NagiosConfig::Value
25
+ node :trailing_comment, NagiosConfig::TrailingComment
26
+ end
27
+
28
+ class Define < Node
29
+ node :type, NagiosConfig::Type
30
+ node :comment, NagiosConfig::Comment
31
+ node :trailing_comment, NagiosConfig::TrailingComment
32
+ nodes :whitespace, NagiosConfig::Whitespace
33
+ nodes :variables, NagiosConfig::Variable
34
+ end
35
+
36
+ class Config < Node
37
+ node :comment, NagiosConfig::Comment
38
+ nodes :whitespace, NagiosConfig::Whitespace
39
+ nodes :variables, NagiosConfig::Variable
40
+ nodes :defines, NagiosConfig::Define
41
+ end
42
+ end
@@ -0,0 +1,100 @@
1
+ module NagiosConfig
2
+
3
+ # Usage:
4
+ # conf = NagiosConfig::Builder.new
5
+ #
6
+ # conf.foo = "bar"
7
+ # conf.define("test") do |test|
8
+ # test.a = "b"
9
+ # test.a.comment("foo")
10
+ # end
11
+ #
12
+ # puts conf
13
+ class Builder
14
+ attr_accessor :root
15
+
16
+ def initialize(root=NagiosConfig::Config.new)
17
+ self.root = root
18
+ end
19
+
20
+ def [](name)
21
+ var = get_variable_named(name)
22
+ if var
23
+ extend(var.val.value, var)
24
+ end
25
+ end
26
+
27
+ def []=(name, value)
28
+ set_variable_named(name, value)
29
+ value
30
+ end
31
+
32
+ def define(type)
33
+ raise "can't define in a define" if root.is_a?(NagiosConfig::Define)
34
+ define = NagiosConfig::Define.new
35
+ define.add_node(NagiosConfig::Type.new(type.to_s))
36
+ root.add_node(define)
37
+ yield self.class.new(define)
38
+ define
39
+ end
40
+
41
+ def break
42
+ root.add_node(NagiosConfig::Whitespace.new("\n"))
43
+ end
44
+
45
+ def comment(string)
46
+ root.add_node(NagiosConfig::Comment.new(string))
47
+ end
48
+
49
+ def to_s
50
+ NagiosConfig::Formater.new.format(root)
51
+ end
52
+
53
+ def method_missing(name, *args)
54
+ if name.to_s =~ /=$/ && args.length == 1
55
+ self[name.to_s.chomp("=")] = args.first
56
+ elsif args.empty?
57
+ self[name]
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ private
64
+ def get_variable_named(name)
65
+ root.nodes.find do |node|
66
+ node.is_a?(NagiosConfig::Variable) && node.name.value == name.to_s
67
+ end
68
+ end
69
+
70
+ def set_variable_named(name, value)
71
+ var = get_variable_named(name)
72
+ if !var && !value.nil?
73
+ var = NagiosConfig::Variable.new
74
+ var.add_node(NagiosConfig::Name.new(name))
75
+ var.add_node(NagiosConfig::Value.new)
76
+ root.add_node(var)
77
+ end
78
+ if value.nil?
79
+ root.remove_node(var)
80
+ elsif value == true
81
+ var.val.value = "1"
82
+ elsif value == false
83
+ var.val.value = "0"
84
+ else
85
+ var.val.value = value.to_s
86
+ end
87
+ var
88
+ end
89
+
90
+ def extend(value, parent)
91
+ metaclass = class << value; self; end
92
+ metaclass.send(:define_method, :comment) do |string|
93
+ parent.add_node(NagiosConfig::TrailingComment.new(string))
94
+ end
95
+ value
96
+ end
97
+
98
+
99
+ end
100
+ end
@@ -0,0 +1,4 @@
1
+ module NagiosConfig
2
+ class ParseError < RuntimeError; end
3
+ class ParentNotFound < RuntimeError; end
4
+ end
@@ -0,0 +1,72 @@
1
+ module NagiosConfig
2
+ class Formater
3
+ attr_accessor :buffer, :in_define, :define_indent, :define_name_width, :define_variable_width
4
+
5
+ def initialize(buffer="")
6
+ self.buffer = buffer
7
+ self.define_indent = 2
8
+ self.define_name_width = 2
9
+ self.define_variable_width = 2
10
+ end
11
+
12
+ def format(root)
13
+ root.nodes.each do |node|
14
+ op = "format_#{node.class.name.sub(/^NagiosConfig::/, "").gsub(/::/, "_")}"
15
+ send(op, node)
16
+ end
17
+ buffer
18
+ end
19
+ alias format_Config format
20
+
21
+ def format_Comment(comment)
22
+ if comment.value.empty?
23
+ buffer << "#\n"
24
+ else
25
+ buffer << comment.value.split(/\n/).map do |comment|
26
+ "##{comment}\n"
27
+ end.join
28
+ end
29
+ end
30
+
31
+ def format_Whitespace(whitespace)
32
+ buffer << whitespace.value
33
+ end
34
+
35
+ def format_Variable(variable)
36
+ if in_define
37
+ format = "#{" " * define_indent}%-#{define_name_width}s%s"
38
+ else
39
+ format = "%s=%s"
40
+ end
41
+ var_string = format % [variable.name.value, variable.val.value]
42
+ if variable.trailing_comment
43
+ var_string = "%-#{define_variable_width}s;%s" % [var_string, variable.trailing_comment.value]
44
+ end
45
+ buffer << var_string << "\n"
46
+ end
47
+
48
+ def format_Define(define)
49
+ buffer << "define "
50
+ name_width = define.variables.map(&:name).map(&:value).map(&:length).max || 0
51
+ value_width = define.variables.map(&:val).map(&:value).map(&:length).max || 0
52
+ variable_width = define_indent + define_name_width + name_width + value_width
53
+
54
+ self.define_name_width += name_width
55
+ self.define_variable_width += variable_width
56
+ self.in_define = true
57
+
58
+ format(define)
59
+
60
+ self.in_define = false
61
+ self.define_variable_width -= variable_width
62
+ self.define_name_width -= name_width
63
+
64
+ buffer << "}\n"
65
+ end
66
+
67
+ def format_Type(type)
68
+ buffer << "#{type.value} {\n"
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,74 @@
1
+ module NagiosConfig
2
+ class Node
3
+ attr_accessor :nodes, :value
4
+
5
+ def initialize(value=nil)
6
+ self.value = value
7
+ self.nodes = []
8
+ end
9
+
10
+ def self.allow(*node_types)
11
+ if node_types.any?
12
+ allow.push(*node_types)
13
+ else
14
+ @allowed_node_types ||= []
15
+ end
16
+ end
17
+
18
+ def self.nodes(name, klass, singular=name.to_s.chomp("s"))
19
+ define_method(name) do
20
+ nodes.select {|n| n.is_a?(klass)}
21
+ end
22
+ alias_method :"add_#{singular}", :add_node
23
+ allow(klass)
24
+ yield klass if block_given?
25
+ end
26
+
27
+ def self.node(name, klass=generate_node_type(name))
28
+ define_method(name) do
29
+ nodes.find {|n| n.is_a?(klass)}
30
+ end
31
+ define_method("#{name}=") do |value|
32
+ remove_node(name)
33
+ add_node(value) if value
34
+ end
35
+ allow(klass)
36
+ yield klass if block_given?
37
+ end
38
+
39
+ def allow?(node)
40
+ self.class.allow.include?(node.class)
41
+ end
42
+
43
+ def add_node(node)
44
+ raise "node type #{node.class} not allowed in #{self.class}" unless allow?(node)
45
+ nodes << node
46
+ self
47
+ end
48
+
49
+ def remove_node(node)
50
+ nodes.delete(node)
51
+ self
52
+ end
53
+
54
+ def after(node)
55
+ nodes[nodes.index(node) + 1]
56
+ end
57
+
58
+ def before(node)
59
+ index = nodes.index(node) - 1
60
+ if index >= 0
61
+ nodes[index]
62
+ end
63
+ end
64
+
65
+ def insert_before(position_node, node)
66
+ nodes.insert(nodes.index(position_node), node)
67
+ end
68
+
69
+ def insert_after(position_node, node)
70
+ nodes.insert(nodes.index(position_node) + 1, node)
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,115 @@
1
+ module NagiosConfig
2
+ class Object
3
+ @@all = []
4
+ @@template_cache = {}
5
+ attr_accessor :type, :own_variables, :objectspace, :parent
6
+
7
+ def initialize(type, variables={}, objectspace=@@all)
8
+ self.type = type.to_sym
9
+ self.own_variables = Hash[variables.map {|k,v| [k.to_sym,v]}]
10
+ self.objectspace = objectspace
11
+ end
12
+
13
+ def self.from_node(node, objectspace=@@all)
14
+ instance = new(node.type.value, {}, objectspace)
15
+ node.variables.each do |variable|
16
+ instance[variable.name.value] = variable.val.value
17
+ end
18
+ instance
19
+ end
20
+
21
+ def self.find_template(type, name, objectspace=@@all)
22
+ type = type.to_sym
23
+ name = name.to_s
24
+ key = [type, name, objectspace.object_id]
25
+ cached = @@template_cache[key]
26
+
27
+ if cached && cached.type == type && cached.name == name
28
+ cached
29
+ else
30
+ @@template_cache[key] = objectspace.find do |obj|
31
+ obj.type == type && obj.name == name
32
+ end
33
+ end
34
+ end
35
+
36
+ def self.clear_cache
37
+ @@template_cache.clear
38
+ end
39
+
40
+ def self.clear
41
+ objectspace.clear
42
+ clear_cache
43
+ nil
44
+ end
45
+
46
+ def self.objectspace
47
+ @@all
48
+ end
49
+
50
+ def parent
51
+ use = own_variables[:use]
52
+ if use
53
+ parent = self.class.find_template(type, use, objectspace)
54
+ raise ParentNotFound.new("can't use #{use}") unless parent
55
+ parent
56
+ end
57
+ end
58
+
59
+ def [](name)
60
+ name = name.to_sym
61
+ result = own_variables[name]
62
+ if result
63
+ result
64
+ elsif own_variables[:use] && name != :name && name != :register
65
+ parent[name]
66
+ end
67
+ end
68
+
69
+ def []=(name, value)
70
+ own_variables[name.to_sym] = value
71
+ end
72
+
73
+ def ==(other)
74
+ other.is_a?(self.class) && other.type == type &&
75
+ other.variables == variables
76
+ end
77
+
78
+ def objectspace=(value)
79
+ @objectspace.delete(self) if @objectspace
80
+ value.push(self) if value
81
+ @objectspace = value
82
+ end
83
+
84
+ def inspect
85
+ "#<#{self.class.name}:#{object_id} @type=#{type}, " <<
86
+ "@objectspace=#{objectspace.class.name}:#{objectspace.object_id}" <<
87
+ "(#{objectspace.length} items), @own_variables=#{own_variables.inspect}>"
88
+ end
89
+
90
+ def method_missing(name, *args)
91
+ if name.to_s !~ /=$/ && args.empty?
92
+ self[name.to_sym]
93
+ elsif name.to_s =~ /=$/ && args.length == 1
94
+ self[name.to_s.chomp("=").to_sym] = args.first
95
+ else
96
+ super
97
+ end
98
+ end
99
+
100
+ protected
101
+ def variables
102
+ parent_variables = parent.variables if parent
103
+ if parent_variables
104
+ parent_variables.delete(:name)
105
+ parent_variables.delete(:register)
106
+ variables = parent_variables.merge(own_variables)
107
+ variables.delete(:use)
108
+ variables
109
+ else
110
+ own_variables.dup
111
+ end
112
+ end
113
+
114
+ end
115
+ end
@@ -0,0 +1,218 @@
1
+ require 'strscan'
2
+ require 'stringio'
3
+ require 'rubygems'
4
+ require 'events'
5
+
6
+ module NagiosConfig
7
+ class Parser
8
+ attr_accessor :scanner, :state, :in_define, :value_buffer
9
+ include Events::Emitter
10
+
11
+ def initialize
12
+ @state = :body
13
+ self.scanner = StringScanner.new("")
14
+ self.value_buffer = ""
15
+ end
16
+
17
+ def parse(io)
18
+ root = NagiosConfig::Config.new
19
+ current_define = nil
20
+ current_variable = nil
21
+ on(:comment) do |comment|
22
+ (current_define || root).add_node(NagiosConfig::Comment.new(comment))
23
+ end
24
+ on(:whitespace) do |whitespace|
25
+ (current_define || root).add_node(NagiosConfig::Whitespace.new(whitespace))
26
+ end
27
+ on(:trailing_comment) do |comment|
28
+ (current_define || root).nodes.last.add_node(NagiosConfig::TrailingComment.new(comment))
29
+ end
30
+ on(:name) do |name|
31
+ current_variable = NagiosConfig::Variable.new
32
+ current_variable.add_node(NagiosConfig::Name.new(name))
33
+ (current_define || root).add_node(current_variable)
34
+ end
35
+ on(:value) do |value|
36
+ current_variable.add_node(NagiosConfig::Value.new(value))
37
+ current_variable = nil
38
+ end
39
+ on(:begin_define) do
40
+ current_define = NagiosConfig::Define.new
41
+ root.add_node(current_define)
42
+ end
43
+ on(:type) do |type|
44
+ current_define.add_node(NagiosConfig::Type.new(type))
45
+ end
46
+ on(:finish_define) do
47
+ current_define = nil
48
+ end
49
+ stream_parse(io)
50
+ root
51
+ end
52
+
53
+ def stream_parse(io)
54
+ io = StringIO.new(io) unless io.respond_to?(:read)
55
+ until io.eof?
56
+ self << io.read(1024)
57
+ end
58
+ end
59
+
60
+ def <<(string)
61
+ scanner.string.replace(scanner.rest)
62
+ scanner.reset
63
+ scanner << string
64
+ self.state = send(state)
65
+ end
66
+
67
+ private
68
+ def body
69
+ empty_line || leading_whitespace || comment || definition || name || :body
70
+ end
71
+ alias start body
72
+
73
+ def empty_line
74
+ whitespace = scanner.scan(/[ \t]*\n/)
75
+ if whitespace
76
+ emit(:whitespace, whitespace)
77
+ in_define ? definition_body : body
78
+ elsif in_define && whitespace = scanner.scan(/[ \t]*(?=;)/) && trailing_comment
79
+ emit(:whitespace, whitespace)
80
+ definition_body
81
+ end
82
+ end
83
+
84
+ def leading_whitespace
85
+ if scanner.scan(/[ \t]+[^\s]/)
86
+ raise ParseError.new("leading whitespace not allowed")
87
+ end
88
+ end
89
+
90
+ def comment
91
+ comment = scanner.scan(/[ \t]*#.*(\n)/)
92
+ if comment
93
+ comment.lstrip!
94
+ comment.slice!(0)
95
+ comment.chomp!("\n")
96
+ emit(:comment, comment)
97
+ in_define ? definition_body : body
98
+ elsif scanner.check(/#/)
99
+ :comment
100
+ end
101
+ end
102
+
103
+ def name
104
+ name = scanner.scan(/[^\s=]+=/)
105
+ if name
106
+ name.chomp!("=")
107
+ emit(:name, name)
108
+ value
109
+ elsif scanner.scan(/.+\n/)
110
+ raise ParseError.new("expected variable definition")
111
+ elsif scanner.check(/[^\s]+/) && !scanner.check(/d(e(f(i(n(e?))?)?)?)?\Z/)
112
+ :name
113
+ end
114
+ end
115
+
116
+ def value
117
+ value = scanner.scan(/.*\n/)
118
+ if value
119
+ value = value_buffer + value
120
+ value.chomp!("\n")
121
+ raise ParseError.new("value expected") if value.empty?
122
+ emit(:value, value)
123
+ self.value_buffer = ""
124
+ body
125
+ elsif value = scanner.scan(/.+/)
126
+ value_buffer << value
127
+ :value
128
+ else
129
+ :value
130
+ end
131
+ end
132
+
133
+ def definition
134
+ if scanner.skip(/define[ \t]/)
135
+ emit(:begin_define)
136
+ self.in_define = true
137
+ type
138
+ end
139
+ end
140
+
141
+ def type
142
+ type = scanner.scan(/[^;{]+[ \t]*\{[ \t]*\n/)
143
+ if type
144
+ type.strip!
145
+ type.chomp!("{")
146
+ type.strip!
147
+ emit(:type, type)
148
+ definition_body
149
+ elsif scanner.check(/([^;{]+[ \t]*(\{[ \t]*)?)?\Z/)
150
+ :type
151
+ else
152
+ raise ParseError.new("type expected")
153
+ end
154
+ end
155
+
156
+ def definition_body
157
+ finish_definition || empty_line || comment || definition_name || :definition_body
158
+ end
159
+
160
+ def definition_name
161
+ name = scanner.scan(/[ \t]*[^\s;#]+[ \t]+/)
162
+ if name
163
+ name.strip!
164
+ emit(:name, name)
165
+ definition_value
166
+ elsif scanner.check(/[ \t]*[^\s#;}]+\Z/)
167
+ :definition_name
168
+ elsif scanner.scan(/[ \t]*[^\s#;]+\n/)
169
+ raise ParseError.new("value expected")
170
+ end
171
+ end
172
+
173
+ def definition_value
174
+ value = scanner.scan(/[^\n;#]*(?=(\n|;))/)
175
+ if value
176
+ value = value_buffer + value
177
+ value.strip!
178
+ raise ParseError.new("value expected") if value.empty?
179
+ emit(:value, value)
180
+ self.value_buffer = ""
181
+ after_value
182
+ elsif value = scanner.scan(/[^\n;#]+/)
183
+ value_buffer << value
184
+ :definition_value
185
+ else
186
+ :definition_value
187
+ end
188
+ end
189
+
190
+ def after_value
191
+ if scanner.skip(/[ \t]*\n/) || trailing_comment
192
+ definition_body
193
+ else
194
+ :after_value
195
+ end
196
+ end
197
+
198
+ def finish_definition
199
+ if scanner.scan(/[ \t]*\}[ \t]*\n/)
200
+ emit(:finish_define)
201
+ self.in_define = false
202
+ body
203
+ end
204
+ end
205
+
206
+ def trailing_comment
207
+ trailing_comment = scanner.scan(/[ \t]*;.*\n/)
208
+ if trailing_comment
209
+ trailing_comment.strip!
210
+ trailing_comment.chomp!("\n")
211
+ trailing_comment.slice!(0)
212
+ emit(:trailing_comment, trailing_comment)
213
+ end
214
+ trailing_comment
215
+ end
216
+
217
+ end
218
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nagios_config
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Matthew Sadler
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-31 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: events
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 63
30
+ segments:
31
+ - 0
32
+ - 9
33
+ - 2
34
+ version: 0.9.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: Read and write Nagios config files from Ruby
38
+ email: mat@sourcetagsandcodes.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - README.rdoc
45
+ files:
46
+ - lib/nagios_config/ast.rb
47
+ - lib/nagios_config/builder.rb
48
+ - lib/nagios_config/errors.rb
49
+ - lib/nagios_config/formater.rb
50
+ - lib/nagios_config/node.rb
51
+ - lib/nagios_config/object.rb
52
+ - lib/nagios_config/parser.rb
53
+ - lib/nagios_config.rb
54
+ - README.rdoc
55
+ has_rdoc: true
56
+ homepage: http://github.com/matsadler/nagios_config
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --main
62
+ - README.rdoc
63
+ - --charset
64
+ - utf-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.7
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Nagios config parser and friends
92
+ test_files: []
93
+