nagios_config 0.0.1

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/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
+