nagiosharder 0.5.0.rc1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -2
- data/Gemfile.lock +43 -24
- data/README.md +186 -0
- data/bin/nagiosharder +1 -1
- data/lib/nagiosharder.rb +340 -115
- data/lib/nagiosharder/cli.rb +75 -7
- data/lib/nagiosharder/commands.rb +173 -0
- data/lib/nagiosharder/filters.rb +7 -0
- data/nagiosharder.gemspec +14 -12
- data/spec/site_spec.rb +141 -0
- data/spec/spec_helper.rb +2 -0
- metadata +49 -46
- data/README.rdoc +0 -100
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 71649e8cef37e7a633343f8f23398b9b5d2ce993
|
4
|
+
data.tar.gz: 392dddb4fb37dae6e118f094cc75afb55e6e5e9f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28cde9bab1474bb38be4d8624b7d10737a921a671d8ca596aa39b03036e3f2368057c136466dd70b733d46efcfe8cfcaf79cf5971766a73ce301b29f66831d70
|
7
|
+
data.tar.gz: 48944c9bd6bc733314439726c60ff8568ea979e66df007c7be966a119d4721bf43bd5b8a4e8d353aaf1d91a7e5cfee6a0b7ccbbb80f9df41f47cc55a2e367a8e
|
data/Gemfile
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gemspec
|
3
|
+
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,42 +1,60 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
nagiosharder (0.
|
4
|
+
nagiosharder (0.5.0.rc1)
|
5
5
|
activesupport
|
6
6
|
hashie (~> 1.2.0)
|
7
|
-
httparty
|
7
|
+
httparty
|
8
8
|
i18n
|
9
9
|
nokogiri
|
10
|
-
rest-client
|
10
|
+
rest-client
|
11
11
|
terminal-table
|
12
12
|
|
13
13
|
GEM
|
14
|
-
remote:
|
14
|
+
remote: https://rubygems.org/
|
15
15
|
specs:
|
16
|
-
activesupport (
|
17
|
-
i18n (~> 0.6)
|
18
|
-
|
19
|
-
|
16
|
+
activesupport (4.0.0)
|
17
|
+
i18n (~> 0.6, >= 0.6.4)
|
18
|
+
minitest (~> 4.2)
|
19
|
+
multi_json (~> 1.3)
|
20
|
+
thread_safe (~> 0.1)
|
21
|
+
tzinfo (~> 0.3.37)
|
22
|
+
addressable (2.3.5)
|
23
|
+
atomic (1.1.14)
|
24
|
+
crack (0.4.1)
|
25
|
+
safe_yaml (~> 0.9.0)
|
26
|
+
diff-lcs (1.2.4)
|
20
27
|
hashie (1.2.0)
|
21
|
-
httparty (0.
|
22
|
-
|
23
|
-
multi_xml
|
24
|
-
i18n (0.6.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
httparty (0.12.0)
|
29
|
+
json (~> 1.8)
|
30
|
+
multi_xml (>= 0.5.2)
|
31
|
+
i18n (0.6.5)
|
32
|
+
json (1.8.1)
|
33
|
+
mime-types (2.0)
|
34
|
+
mini_portile (0.5.2)
|
35
|
+
minitest (4.7.5)
|
36
|
+
multi_json (1.8.2)
|
37
|
+
multi_xml (0.5.5)
|
38
|
+
nokogiri (1.6.0)
|
39
|
+
mini_portile (~> 0.5.0)
|
29
40
|
rest-client (1.6.7)
|
30
41
|
mime-types (>= 1.16)
|
31
|
-
rspec (2.
|
32
|
-
rspec-core (~> 2.
|
33
|
-
rspec-expectations (~> 2.
|
34
|
-
rspec-mocks (~> 2.
|
35
|
-
rspec-core (2.
|
36
|
-
rspec-expectations (2.
|
37
|
-
diff-lcs (
|
38
|
-
rspec-mocks (2.
|
42
|
+
rspec (2.14.1)
|
43
|
+
rspec-core (~> 2.14.0)
|
44
|
+
rspec-expectations (~> 2.14.0)
|
45
|
+
rspec-mocks (~> 2.14.0)
|
46
|
+
rspec-core (2.14.6)
|
47
|
+
rspec-expectations (2.14.3)
|
48
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
49
|
+
rspec-mocks (2.14.4)
|
50
|
+
safe_yaml (0.9.7)
|
39
51
|
terminal-table (1.4.5)
|
52
|
+
thread_safe (0.1.3)
|
53
|
+
atomic
|
54
|
+
tzinfo (0.3.38)
|
55
|
+
webmock (1.15.0)
|
56
|
+
addressable (>= 2.2.7)
|
57
|
+
crack (>= 0.3.2)
|
40
58
|
|
41
59
|
PLATFORMS
|
42
60
|
ruby
|
@@ -44,3 +62,4 @@ PLATFORMS
|
|
44
62
|
DEPENDENCIES
|
45
63
|
nagiosharder!
|
46
64
|
rspec (>= 1.2.9)
|
65
|
+
webmock
|
data/README.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
# nagiosharder
|
2
|
+
|
3
|
+
Query and command a Nagios install using the power of ruby (and lots of screen-scaping)! Do the usual gem install jig:
|
4
|
+
|
5
|
+
gem install nagiosharder
|
6
|
+
|
7
|
+
Now you have access to both a Ruby interface and a command line interface.
|
8
|
+
|
9
|
+
Here are some examples to get you started with the Ruby API:
|
10
|
+
|
11
|
+
require 'nagiosharder'
|
12
|
+
|
13
|
+
cgi = 'https://path/to/nagios/cgi/directory'
|
14
|
+
user = 'user'
|
15
|
+
pass = 'pass'
|
16
|
+
version = 3
|
17
|
+
time_format = 'iso8601'
|
18
|
+
verify_ssl = true
|
19
|
+
|
20
|
+
site = NagiosHarder::Site.new(cgi, user, pass, version, time_format, verify_ssl)
|
21
|
+
# version defaults to 3
|
22
|
+
# time_format defaults to 'strict-iso8601' for version 3 and 'us' for all other versions
|
23
|
+
# verify_ssl defaults to true, pass false to override
|
24
|
+
|
25
|
+
Get details back about a host's services:
|
26
|
+
|
27
|
+
puts site.host_status('myhost')
|
28
|
+
|
29
|
+
Schedule a host to have services checks run again right now:
|
30
|
+
|
31
|
+
site.schedule_host_check('myhost')
|
32
|
+
|
33
|
+
Get details on all services:
|
34
|
+
|
35
|
+
site.service_status
|
36
|
+
|
37
|
+
Or just things with problems:
|
38
|
+
|
39
|
+
site.service_status(
|
40
|
+
:service_status_types => [
|
41
|
+
:critical,
|
42
|
+
:warning,
|
43
|
+
:unknown
|
44
|
+
]
|
45
|
+
)
|
46
|
+
|
47
|
+
Or just muted services, sorted desc by duration:
|
48
|
+
|
49
|
+
site.service_status(
|
50
|
+
:service_props => [
|
51
|
+
:notifications_disabled,
|
52
|
+
],
|
53
|
+
:sort_type => :descending,
|
54
|
+
:sort_option => :state_duration,
|
55
|
+
)
|
56
|
+
|
57
|
+
Or get the details for a single service group:
|
58
|
+
|
59
|
+
site.service_status(:group => "AWESOME")
|
60
|
+
|
61
|
+
Schedule a host to have services checks run again right now:
|
62
|
+
|
63
|
+
site.schedule_service_check('myhost', 'myservice')
|
64
|
+
|
65
|
+
Schedule 20 minutes of downtime, starting now:
|
66
|
+
|
67
|
+
site.schedule_host_downtime('myhost', :start_time => Time.now, :end_time => Time.now + 20.minutes)
|
68
|
+
|
69
|
+
Schedule a flexible 20 minutes of downtime between now and 2 hours from now:
|
70
|
+
|
71
|
+
site.schedule_host_downtime('myhost', :type => :flexible, :start_time => Time.now, :end_time => Time.now + 2.hours, :hours => 0, :minutes => 20)
|
72
|
+
|
73
|
+
Schedule 20 minutes of downtime for a service, starting now:
|
74
|
+
|
75
|
+
site.schedule_service_downtime('myhost', 'myservice', :start_time => Time.now, :end_time => Time.now + 20.minutes)
|
76
|
+
|
77
|
+
Cancel a scheduled host downtime:
|
78
|
+
|
79
|
+
site.cancel_downtime('downtime_id')
|
80
|
+
|
81
|
+
Cancel a scheduled service downtime:
|
82
|
+
|
83
|
+
site.cancel_downtime('downtime_id', :service_downtime)
|
84
|
+
|
85
|
+
Acknowledge a down service:
|
86
|
+
|
87
|
+
site.acknowledge_service('myhost', 'myservice', 'something bad happened')
|
88
|
+
|
89
|
+
Or unacknowledge a down service:
|
90
|
+
|
91
|
+
site.unacknowledge_service('myhost', 'myservice')
|
92
|
+
|
93
|
+
Acknowledge a down host:
|
94
|
+
|
95
|
+
site.acknowledge_host('myhost', 'something bad happened')
|
96
|
+
|
97
|
+
Or unacknowledge a down host:
|
98
|
+
|
99
|
+
site.unacknowledge_host('myhost')
|
100
|
+
|
101
|
+
Schedule next host check for right now:
|
102
|
+
|
103
|
+
site.schedule_host_check('myhost')
|
104
|
+
|
105
|
+
Schedule next service check for right now:
|
106
|
+
|
107
|
+
site.schedule_service_check('myhost', 'myservice')
|
108
|
+
|
109
|
+
Disable notifications for a service:
|
110
|
+
|
111
|
+
site.disable_service_notifications('myhost', 'myservice')
|
112
|
+
|
113
|
+
Check if notifications are disabled:
|
114
|
+
|
115
|
+
site.service_notifications_disabled?('myhost', 'myservice')
|
116
|
+
|
117
|
+
Enable notifications for a service:
|
118
|
+
|
119
|
+
site.enable_service_notifications('myhost', 'myservice')
|
120
|
+
|
121
|
+
Disable notifications, and wait for nagios to process it:
|
122
|
+
|
123
|
+
site.disable_service_notifications('myhost', 'myservice')
|
124
|
+
until site.service_notifications_disabled?('myhost', 'myservice')
|
125
|
+
sleep 3
|
126
|
+
end
|
127
|
+
|
128
|
+
Get a summary on all hostgroups:
|
129
|
+
|
130
|
+
site.hostgroups_summary
|
131
|
+
|
132
|
+
Or a summary for a specific hostgroup:
|
133
|
+
|
134
|
+
site.hostgroups_summary('myhostgroup')
|
135
|
+
|
136
|
+
Get a summary on all servicegroups:
|
137
|
+
|
138
|
+
site.servicegroups_summary
|
139
|
+
|
140
|
+
Or a summary for a specific servicegroup:
|
141
|
+
|
142
|
+
site.servicegroups_summary('myservicegroup')
|
143
|
+
|
144
|
+
Get detailed output for all hostgroups:
|
145
|
+
|
146
|
+
site.hostgroups_detail
|
147
|
+
|
148
|
+
Get detailed output for a specific hostgroup:
|
149
|
+
|
150
|
+
site.hostgroups_detail('myhostgroup')
|
151
|
+
|
152
|
+
Get alert history:
|
153
|
+
|
154
|
+
site.alert_history
|
155
|
+
|
156
|
+
Or all HARD state alerts:
|
157
|
+
|
158
|
+
site.alert_history(:state_type => :hard, :type => :all)
|
159
|
+
|
160
|
+
---
|
161
|
+
|
162
|
+
Then there's the command line. Start with --help
|
163
|
+
|
164
|
+
nagiosharder --help
|
165
|
+
|
166
|
+
This will show you how you configure nagiosharder enough to talk to your nagios. You need at least a username, password, and nagios url. These can alternatively be in a config file.
|
167
|
+
|
168
|
+
For example:
|
169
|
+
|
170
|
+
nagiosharder --config /path/to/yaml
|
171
|
+
|
172
|
+
This will display all available commands.
|
173
|
+
|
174
|
+
---
|
175
|
+
|
176
|
+
#### Note on Patches/Pull Requests
|
177
|
+
|
178
|
+
* Fork the project.
|
179
|
+
* Make your feature addition or bug fix.
|
180
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
181
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
182
|
+
* Send me a pull request. Bonus points for topic branches.
|
183
|
+
|
184
|
+
#### Copyright
|
185
|
+
|
186
|
+
Copyright (c) 2010 Josh Nichols. See LICENSE for details.
|
data/bin/nagiosharder
CHANGED
data/lib/nagiosharder.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require 'restclient'
|
2
4
|
require 'nokogiri'
|
3
5
|
require 'active_support' # fine, we'll just do all of activesupport instead of the parts I want. thank Rails 3 for shuffling requires around.
|
4
6
|
require 'cgi'
|
5
7
|
require 'hashie'
|
6
8
|
require 'nagiosharder/filters'
|
9
|
+
require 'nagiosharder/commands'
|
7
10
|
|
8
11
|
# :(
|
9
12
|
require 'active_support/version' # double and triplely ensure ActiveSupport::VERSION is around
|
@@ -25,169 +28,192 @@ class NagiosHarder
|
|
25
28
|
attr_accessor :nagios_url, :user, :password, :default_options, :default_cookies, :version, :nagios_time_format
|
26
29
|
include HTTParty::ClassMethods
|
27
30
|
|
28
|
-
def initialize(nagios_url, user, password, version = 3, nagios_time_format = nil)
|
31
|
+
def initialize(nagios_url, user, password, version = 3, nagios_time_format = nil, ssl_verify = true)
|
29
32
|
@nagios_url = nagios_url.gsub(/\/$/, '')
|
30
33
|
@user = user
|
31
34
|
@password = password
|
32
|
-
@default_options = {}
|
35
|
+
@default_options = {:verify => ssl_verify}
|
33
36
|
@default_cookies = {}
|
34
37
|
@version = version
|
35
38
|
debug_output if ENV['DEBUG']
|
36
39
|
basic_auth(@user, @password) if @user && @password
|
37
|
-
@nagios_time_format =
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
@nagios_time_format = case nagios_time_format
|
41
|
+
when 'us'
|
42
|
+
"%m-%d-%Y %H:%M:%S"
|
43
|
+
when 'euro'
|
44
|
+
"%d-%m-%Y %H:%M:%S"
|
45
|
+
when 'iso8601'
|
46
|
+
"%Y-%m-%d %H:%M:%S"
|
47
|
+
else
|
48
|
+
if @version.to_i == 3 # allows compatability with nagios 4
|
49
|
+
"%Y-%m-%dT%H:%M:%S"
|
50
|
+
else
|
51
|
+
"%m-%d-%Y %H:%M:%S"
|
52
|
+
end
|
53
|
+
end
|
46
54
|
self
|
47
55
|
end
|
48
56
|
|
49
|
-
def
|
57
|
+
def post_command(body)
|
58
|
+
# cmd_mod is always CMDMODE_COMMIT
|
59
|
+
body = {:cmd_mod => 2}.merge(body)
|
60
|
+
response = post(cmd_url, :body => body)
|
61
|
+
response.code == 200 && response.body.match(/successful/) && true
|
62
|
+
end
|
63
|
+
|
64
|
+
def acknowledge_host(host, comment)
|
50
65
|
request = {
|
51
|
-
:cmd_typ =>
|
52
|
-
:cmd_mod => 2,
|
66
|
+
:cmd_typ => COMMANDS[:acknowledge_host_problem],
|
53
67
|
:com_author => @user,
|
54
68
|
:com_data => comment,
|
55
69
|
:host => host,
|
56
|
-
:service => service,
|
57
70
|
:send_notification => true,
|
58
71
|
:persistent => false,
|
59
72
|
:sticky_ack => true
|
60
73
|
}
|
61
74
|
|
62
|
-
|
63
|
-
response.code == 200 && response.body =~ /successful/
|
75
|
+
post_command(request)
|
64
76
|
end
|
65
77
|
|
66
|
-
def
|
78
|
+
def unacknowledge_host(host)
|
67
79
|
request = {
|
68
|
-
:cmd_typ =>
|
69
|
-
:
|
80
|
+
:cmd_typ => COMMANDS[:remove_host_acknowledgement],
|
81
|
+
:host => host
|
82
|
+
}
|
83
|
+
|
84
|
+
post_command(request)
|
85
|
+
end
|
86
|
+
|
87
|
+
def acknowledge_service(host, service, comment)
|
88
|
+
request = {
|
89
|
+
:cmd_typ => COMMANDS[:acknowledge_service_problem],
|
70
90
|
:com_author => @user,
|
71
91
|
:com_data => comment,
|
72
92
|
:host => host,
|
93
|
+
:service => service,
|
73
94
|
:send_notification => true,
|
74
95
|
:persistent => false,
|
75
96
|
:sticky_ack => true
|
76
97
|
}
|
77
98
|
|
78
|
-
|
79
|
-
response.code == 200 && response.body =~ /successful/
|
99
|
+
post_command(request)
|
80
100
|
end
|
81
|
-
|
101
|
+
|
82
102
|
def unacknowledge_service(host, service)
|
83
103
|
request = {
|
84
|
-
:cmd_typ =>
|
85
|
-
:cmd_mod => 2,
|
104
|
+
:cmd_typ => COMMANDS[:remove_service_acknowledgement],
|
86
105
|
:host => host,
|
87
106
|
:service => service
|
88
107
|
}
|
89
108
|
|
90
|
-
|
91
|
-
response.code == 200 && response.body =~ /successful/
|
109
|
+
post_command(request)
|
92
110
|
end
|
93
111
|
|
94
|
-
def
|
112
|
+
def schedule_host_downtime(host, options = {})
|
113
|
+
options[:type] ||= :fixed
|
114
|
+
|
95
115
|
request = {
|
96
|
-
:
|
97
|
-
:cmd_typ => 56,
|
116
|
+
:cmd_typ => COMMANDS[:schedule_host_downtime],
|
98
117
|
:com_author => options[:author] || "#{@user} via nagiosharder",
|
99
118
|
:com_data => options[:comment] || 'scheduled downtime by nagiosharder',
|
100
119
|
:host => host,
|
101
|
-
:
|
120
|
+
:childoptions => 0,
|
102
121
|
:trigger => 0
|
103
122
|
}
|
104
123
|
|
124
|
+
# FIXME we could use some option checking...
|
125
|
+
|
105
126
|
request[:fixed] = case options[:type].to_sym
|
106
127
|
when :fixed then 1
|
107
128
|
when :flexible then 0
|
108
|
-
else 1
|
129
|
+
else 1 # default to fixed
|
109
130
|
end
|
110
131
|
|
111
|
-
|
112
|
-
if request[:fixed] == 0
|
132
|
+
if request[:fixed] == 0
|
113
133
|
request[:hours] = options[:hours]
|
114
134
|
request[:minutes] = options[:minutes]
|
115
135
|
end
|
116
136
|
|
117
|
-
request[:start_time] = formatted_time_for(options[:start_time])
|
118
|
-
request[:end_time] = formatted_time_for(options[:end_time])
|
137
|
+
request[:start_time] = formatted_time_for(options[:start_time] || Time.now)
|
138
|
+
request[:end_time] = formatted_time_for(options[:end_time] || Time.now + 1.hour)
|
119
139
|
|
120
|
-
|
121
|
-
|
122
|
-
response.code == 200 && response.body =~ /successful/
|
140
|
+
post_command(request)
|
123
141
|
end
|
142
|
+
|
143
|
+
def schedule_service_downtime(host, service, options = {})
|
144
|
+
options[:type] ||= :fixed
|
124
145
|
|
125
|
-
def schedule_host_downtime(host, options = {})
|
126
146
|
request = {
|
127
|
-
:
|
128
|
-
:cmd_typ => 55,
|
147
|
+
:cmd_typ => COMMANDS[:schedule_service_downtime],
|
129
148
|
:com_author => options[:author] || "#{@user} via nagiosharder",
|
130
149
|
:com_data => options[:comment] || 'scheduled downtime by nagiosharder',
|
131
150
|
:host => host,
|
132
|
-
:
|
151
|
+
:service => service,
|
133
152
|
:trigger => 0
|
134
153
|
}
|
135
154
|
|
136
|
-
# FIXME we could use some option checking...
|
137
|
-
|
138
155
|
request[:fixed] = case options[:type].to_sym
|
139
156
|
when :fixed then 1
|
140
157
|
when :flexible then 0
|
141
|
-
else 1
|
158
|
+
else 1
|
142
159
|
end
|
143
160
|
|
144
|
-
|
161
|
+
|
162
|
+
if request[:fixed] == 0
|
145
163
|
request[:hours] = options[:hours]
|
146
164
|
request[:minutes] = options[:minutes]
|
147
165
|
end
|
148
166
|
|
149
|
-
request[:start_time] = formatted_time_for(options[:start_time])
|
150
|
-
request[:end_time] = formatted_time_for(options[:end_time])
|
167
|
+
request[:start_time] = formatted_time_for(options[:start_time] || Time.now)
|
168
|
+
request[:end_time] = formatted_time_for(options[:end_time] || Time.now + 1.hour)
|
151
169
|
|
152
|
-
|
153
|
-
|
154
|
-
response.code == 200 && response.body =~ /successful/
|
170
|
+
post_command(request)
|
155
171
|
end
|
156
172
|
|
157
173
|
def cancel_downtime(downtime_id, downtime_type = :host_downtime)
|
158
|
-
|
159
|
-
:
|
160
|
-
:
|
174
|
+
request = {
|
175
|
+
:cmd_typ => COMMANDS["del_#{downtime_type}".to_sym],
|
176
|
+
:down_id => downtime_id
|
161
177
|
}
|
162
|
-
|
163
|
-
|
164
|
-
:cmd_mod => 2,
|
165
|
-
:down_id => downtime_id
|
166
|
-
})
|
167
|
-
response.code == 200 && response.body =~ /successful/
|
178
|
+
|
179
|
+
post_command(request)
|
168
180
|
end
|
169
181
|
|
170
182
|
def schedule_host_check(host)
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
183
|
+
request = {
|
184
|
+
:start_time => formatted_time_for(Time.now),
|
185
|
+
:host => host,
|
186
|
+
:force_check => true,
|
187
|
+
:cmd_typ => COMMANDS[:schedule_host_check],
|
188
|
+
}
|
189
|
+
|
190
|
+
post_command(request)
|
179
191
|
end
|
180
192
|
|
181
193
|
def schedule_service_check(host, service)
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
194
|
+
request = {
|
195
|
+
:start_time => formatted_time_for(Time.now),
|
196
|
+
:host => host,
|
197
|
+
:service => service,
|
198
|
+
:force_check => true,
|
199
|
+
:cmd_typ => COMMANDS[:schedule_service_check],
|
200
|
+
}
|
201
|
+
|
202
|
+
post_command(request)
|
203
|
+
end
|
204
|
+
|
205
|
+
def host_status(host)
|
206
|
+
host_status_url = "#{status_url}?host=#{host}&embedded=1&noheader=1&limit=0"
|
207
|
+
response = get(host_status_url)
|
208
|
+
|
209
|
+
raise "wtf #{host_status_url}? #{response.code}" unless response.code == 200
|
210
|
+
|
211
|
+
services = {}
|
212
|
+
parse_status_html(response) do |status|
|
213
|
+
services[status[:service]] = status
|
214
|
+
end
|
215
|
+
|
216
|
+
services
|
191
217
|
end
|
192
218
|
|
193
219
|
def service_status(options = {})
|
@@ -215,7 +241,7 @@ class NagiosHarder
|
|
215
241
|
:hostprops,
|
216
242
|
:serviceprops,
|
217
243
|
).each do |key|
|
218
|
-
params[key.to_s] = options[:val] if
|
244
|
+
params[key.to_s] = options[:val] if options[:val] && options[:val].match(/^\d*$/)
|
219
245
|
end
|
220
246
|
|
221
247
|
if @version == 3
|
@@ -223,6 +249,7 @@ class NagiosHarder
|
|
223
249
|
params['style'] = 'detail'
|
224
250
|
params['embedded'] = '1'
|
225
251
|
params['noheader'] = '1'
|
252
|
+
params['limit'] = 0
|
226
253
|
else
|
227
254
|
if options[:group]
|
228
255
|
params['servicegroup'] = options[:group]
|
@@ -246,76 +273,124 @@ class NagiosHarder
|
|
246
273
|
statuses
|
247
274
|
end
|
248
275
|
|
249
|
-
def
|
250
|
-
|
251
|
-
response =
|
276
|
+
def hostgroups_summary(hostgroup = "all")
|
277
|
+
hostgroups_summary_url = "#{status_url}?hostgroup=#{hostgroup}&style=summary"
|
278
|
+
response = get(hostgroups_summary_url)
|
252
279
|
|
253
|
-
raise "wtf #{
|
280
|
+
raise "wtf #{hostgroups_summary_url}? #{response.code}" unless response.code == 200
|
254
281
|
|
255
|
-
|
256
|
-
|
257
|
-
|
282
|
+
hostgroups = {}
|
283
|
+
parse_summary_html(response) do |status|
|
284
|
+
hostgroups[status[:group]] = status
|
258
285
|
end
|
259
286
|
|
260
|
-
|
287
|
+
hostgroups
|
288
|
+
end
|
289
|
+
|
290
|
+
def servicegroups_summary(servicegroup = "all")
|
291
|
+
servicegroups_summary_url = "#{status_url}?servicegroup=#{servicegroup}&style=summary"
|
292
|
+
response = get(servicegroups_summary_url)
|
293
|
+
|
294
|
+
raise "wtf #{servicegroups_summary_url}? #{response.code}" unless response.code == 200
|
295
|
+
|
296
|
+
servicegroups = {}
|
297
|
+
parse_summary_html(response) do |status|
|
298
|
+
servicegroups[status[:group]] = status
|
299
|
+
end
|
300
|
+
|
301
|
+
servicegroups
|
302
|
+
end
|
303
|
+
|
304
|
+
def hostgroups_detail(hostgroup = "all")
|
305
|
+
hostgroups_detail_url = "#{status_url}?hostgroup=#{hostgroup}&style=hostdetail&embedded=1&noheader=1&limit=0"
|
306
|
+
response = get(hostgroups_detail_url)
|
307
|
+
|
308
|
+
raise "wtf #{hostgroups_detail_url}? #{response.code}" unless response.code == 200
|
309
|
+
|
310
|
+
hosts = {}
|
311
|
+
parse_detail_html(response) do |status|
|
312
|
+
hosts[status[:host]] = status
|
313
|
+
end
|
314
|
+
|
315
|
+
hosts
|
261
316
|
end
|
262
317
|
|
263
318
|
def disable_service_notifications(host, service, options = {})
|
264
319
|
request = {
|
265
|
-
:cmd_mod => 2,
|
266
320
|
:host => host
|
267
321
|
}
|
268
322
|
|
269
323
|
if service
|
270
|
-
request[:cmd_typ] =
|
324
|
+
request[:cmd_typ] = COMMANDS[:disable_service_notifications]
|
271
325
|
request[:service] = service
|
272
326
|
else
|
273
|
-
request[:cmd_typ] =
|
327
|
+
request[:cmd_typ] = COMMANDS[:disable_host_service_checks]
|
274
328
|
request[:ahas] = true
|
275
329
|
end
|
276
330
|
|
277
|
-
|
278
|
-
|
279
|
-
# TODO enable waiting. seems to hang intermittently
|
280
|
-
#if options[:wait]
|
281
|
-
# sleep(3) until service_notifications_disabled?(host, service)
|
282
|
-
#end
|
283
|
-
true
|
284
|
-
else
|
285
|
-
false
|
286
|
-
end
|
331
|
+
# TODO add option to block until the service shows as disabled
|
332
|
+
post_command(request)
|
287
333
|
end
|
288
334
|
|
289
335
|
def enable_service_notifications(host, service, options = {})
|
290
336
|
request = {
|
291
|
-
:cmd_mod => 2,
|
292
337
|
:host => host
|
293
338
|
}
|
294
339
|
|
295
340
|
if service
|
296
|
-
request[:cmd_typ] =
|
341
|
+
request[:cmd_typ] = COMMANDS[:enable_service_notifications]
|
297
342
|
request[:service] = service
|
298
343
|
else
|
299
|
-
request[:cmd_typ] =
|
344
|
+
request[:cmd_typ] = COMMANDS[:enable_host_service_notifications]
|
300
345
|
request[:ahas] = true
|
301
346
|
end
|
302
347
|
|
303
|
-
|
304
|
-
|
305
|
-
# TODO enable waiting. seems to hang intermittently
|
306
|
-
#if options[:wait]
|
307
|
-
# sleep(3) while service_notifications_disabled?(host, service)
|
308
|
-
#end
|
309
|
-
true
|
310
|
-
else
|
311
|
-
false
|
312
|
-
end
|
348
|
+
# TODO add option to block until the service shows as disabled
|
349
|
+
post_command(request)
|
313
350
|
end
|
314
351
|
|
315
352
|
def service_notifications_disabled?(host, service)
|
316
353
|
self.host_status(host)[service].notifications_disabled
|
317
354
|
end
|
355
|
+
|
356
|
+
def alert_history(options = {})
|
357
|
+
params = {}
|
358
|
+
|
359
|
+
{
|
360
|
+
:state_type => :history_state,
|
361
|
+
:type => :history
|
362
|
+
}.each do |key, val|
|
363
|
+
if options[key] && (options[key].is_a?(Array) || options[key].is_a?(Symbol))
|
364
|
+
params[key.to_s.gsub(/_/, '')] = Nagiosharder::Filters.value(val, *options[key])
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# if any of the standard filter params are already integers, those win
|
369
|
+
%w(
|
370
|
+
:statetype,
|
371
|
+
:type
|
372
|
+
).each do |key|
|
373
|
+
params[key.to_s] = options[:val] if !options[:val].nil? && options[:val].match(/^\d*$/)
|
374
|
+
end
|
375
|
+
|
376
|
+
params['host'] = options[:host] || 'all'
|
377
|
+
params['archive'] = options[:archive] || '0'
|
378
|
+
|
379
|
+
query = params.select {|k,v| v }.map {|k,v| "#{k}=#{v}" }.join('&')
|
380
|
+
|
381
|
+
alert_history_url = "#{history_url}?#{query}"
|
382
|
+
puts alert_history_url
|
383
|
+
response = get(alert_history_url)
|
318
384
|
|
385
|
+
raise "wtf #{alert_history_url}? #{response.code}" unless response.code == 200
|
386
|
+
|
387
|
+
alerts = []
|
388
|
+
parse_history_html(response) do |alert|
|
389
|
+
alerts << alert
|
390
|
+
end
|
391
|
+
|
392
|
+
alerts
|
393
|
+
end
|
319
394
|
|
320
395
|
def status_url
|
321
396
|
"#{nagios_url}/status.cgi"
|
@@ -328,6 +403,10 @@ class NagiosHarder
|
|
328
403
|
def extinfo_url
|
329
404
|
"#{nagios_url}/extinfo.cgi"
|
330
405
|
end
|
406
|
+
|
407
|
+
def history_url
|
408
|
+
"#{nagios_url}/history.cgi"
|
409
|
+
end
|
331
410
|
|
332
411
|
private
|
333
412
|
|
@@ -335,10 +414,112 @@ class NagiosHarder
|
|
335
414
|
time.strftime(nagios_time_format)
|
336
415
|
end
|
337
416
|
|
338
|
-
def
|
417
|
+
def parse_summary_html(response)
|
339
418
|
doc = Nokogiri::HTML(response.to_s)
|
340
419
|
rows = doc.css('table.status > tr')
|
341
420
|
|
421
|
+
rows.each do |row|
|
422
|
+
columns = Nokogiri::HTML(row.inner_html).css('body > td').to_a
|
423
|
+
if columns.any?
|
424
|
+
|
425
|
+
# Group column
|
426
|
+
group = columns[0].inner_text.gsub(/\n/, '').match(/\((.*?)\)/)[1]
|
427
|
+
end
|
428
|
+
|
429
|
+
if group
|
430
|
+
host_status_url, host_status_counts = parse_host_status_summary(columns[1]) if columns[1]
|
431
|
+
service_status_url, service_status_counts = parse_service_status_summary(columns[2]) if columns[2]
|
432
|
+
|
433
|
+
status = Hashie::Mash.new :group => group,
|
434
|
+
:host_status_url => host_status_url,
|
435
|
+
:host_status_counts => host_status_counts,
|
436
|
+
:service_status_url => service_status_url,
|
437
|
+
:service_status_counts => service_status_counts
|
438
|
+
|
439
|
+
yield status
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def parse_host_status_summary(column)
|
445
|
+
text = column.css('td a')[0]
|
446
|
+
link = text['href'] rescue nil
|
447
|
+
counts = {}
|
448
|
+
counts['up'] = column.inner_text.match(/(\d+)\s(UP)/)[1] rescue 0
|
449
|
+
counts['down'] = column.inner_text.match(/(\d+)\s(DOWN)/)[1] rescue 0
|
450
|
+
return link, counts
|
451
|
+
end
|
452
|
+
|
453
|
+
def parse_service_status_summary(column)
|
454
|
+
text = column.css('td a')[0]
|
455
|
+
link = text['href'] rescue nil
|
456
|
+
counts = {}
|
457
|
+
counts['ok'] = column.inner_text.match(/(\d+)\s(OK)/)[1] rescue 0
|
458
|
+
counts['warning'] = column.inner_text.match(/(\d+)\s(WARNING)/)[1] rescue 0
|
459
|
+
counts['critical'] = column.inner_text.match(/(\d+)\s(CRITICAL)/)[1] rescue 0
|
460
|
+
counts['unknown'] = column.inner_text.match(/(\d+)\s(UNKNOWN)/)[1] rescue 0
|
461
|
+
return link, counts
|
462
|
+
end
|
463
|
+
|
464
|
+
def parse_detail_html(response)
|
465
|
+
doc = Nokogiri::HTML(response.to_s)
|
466
|
+
rows = doc.css('table.status > tr')
|
467
|
+
|
468
|
+
rows.each do |row|
|
469
|
+
columns = Nokogiri::HTML(row.inner_html).css('body > td').to_a
|
470
|
+
if columns.any?
|
471
|
+
|
472
|
+
# Host column
|
473
|
+
host = columns[0].css('a').text.strip
|
474
|
+
|
475
|
+
# Status
|
476
|
+
status = columns[1].inner_html if columns[1]
|
477
|
+
|
478
|
+
# Last Check
|
479
|
+
last_check = if columns[2] && columns[2].inner_html != 'N/A'
|
480
|
+
last_check_str = columns[2].inner_html
|
481
|
+
debug "Need to parse #{columns[2].inner_html} in #{nagios_time_format}"
|
482
|
+
DateTime.strptime(columns[2].inner_html, nagios_time_format).to_s
|
483
|
+
end
|
484
|
+
debug 'parsed last check column'
|
485
|
+
|
486
|
+
# Duration
|
487
|
+
duration = columns[3].inner_html.squeeze(' ').gsub(/^ /, '') if columns[3]
|
488
|
+
started_at = if duration && match_data = duration.match(/^\s*(\d+)d\s+(\d+)h\s+(\d+)m\s+(\d+)s\s*$/)
|
489
|
+
(
|
490
|
+
match_data[1].to_i.days +
|
491
|
+
match_data[2].to_i.hours +
|
492
|
+
match_data[3].to_i.minutes +
|
493
|
+
match_data[4].to_i.seconds
|
494
|
+
).ago
|
495
|
+
end
|
496
|
+
debug 'parsed duration column'
|
497
|
+
|
498
|
+
# Status info
|
499
|
+
status_info = columns[4].inner_html.gsub(' ', '').gsub("\302\240", '').gsub(" ", '') if columns[4]
|
500
|
+
debug 'parsed status info column'
|
501
|
+
|
502
|
+
if host && status && last_check && duration && started_at && status_info
|
503
|
+
host_extinfo_url = "#{extinfo_url}?type=1&host=#{host}"
|
504
|
+
|
505
|
+
status = Hashie::Mash.new :host => host,
|
506
|
+
:status => status,
|
507
|
+
:last_check => last_check,
|
508
|
+
:duration => duration,
|
509
|
+
:started_at => started_at,
|
510
|
+
:extended_info => status_info,
|
511
|
+
:host_extinfo_url => host_extinfo_url
|
512
|
+
|
513
|
+
yield status
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def parse_status_html(response)
|
520
|
+
doc = Nokogiri::HTML(response.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '').to_s)
|
521
|
+
rows = doc.css('table.status > tr')
|
522
|
+
|
342
523
|
last_host = nil
|
343
524
|
rows.each do |row|
|
344
525
|
columns = Nokogiri::HTML(row.inner_html).css('body > td').to_a
|
@@ -374,10 +555,15 @@ class NagiosHarder
|
|
374
555
|
acknowledged = other_links.any? do |link|
|
375
556
|
link.css('img').attribute('src').to_s =~ /ack\.gif/
|
376
557
|
end
|
558
|
+
|
377
559
|
notifications_disabled = other_links.any? do |link|
|
378
560
|
link.css('img').attribute('src').to_s =~ /ndisabled\.gif/
|
379
561
|
end
|
380
562
|
|
563
|
+
downtime = other_links.any? do |link|
|
564
|
+
link.css('img').attribute('src').to_s =~ /downtime\.gif/
|
565
|
+
end
|
566
|
+
|
381
567
|
extra_service_notes_link = other_links.detect do |link|
|
382
568
|
link.css('img').any? do |img|
|
383
569
|
img.attribute('src').to_s =~ /notes\.gif/
|
@@ -441,7 +627,8 @@ class NagiosHarder
|
|
441
627
|
:flapping => flapping,
|
442
628
|
:comments_url => comments_url,
|
443
629
|
:extra_service_notes_url => extra_service_notes_url,
|
444
|
-
:notifications_disabled => notifications_disabled
|
630
|
+
:notifications_disabled => notifications_disabled,
|
631
|
+
:downtime => downtime
|
445
632
|
|
446
633
|
yield status
|
447
634
|
end
|
@@ -450,6 +637,44 @@ class NagiosHarder
|
|
450
637
|
|
451
638
|
nil
|
452
639
|
end
|
640
|
+
|
641
|
+
def parse_history_html(response)
|
642
|
+
doc = Nokogiri::HTML(response.to_s)
|
643
|
+
alerts = doc.css('div.logEntries img')
|
644
|
+
|
645
|
+
if alerts.any?
|
646
|
+
alerts.each do |row|
|
647
|
+
text = row.next.text.gsub(' ',';').split(/;|: /) unless row.next.text.nil?
|
648
|
+
# differentiate host vs service alert output in nagios.log
|
649
|
+
case
|
650
|
+
when text.length >= 8 # service alert
|
651
|
+
last_check, alert_type, host, service, status, state, attempt, *extended_info = row.next.text.gsub(' ',';').split(/;|: /)
|
652
|
+
when text.length == 7 # host alert
|
653
|
+
last_check, alert_type, host, status, state, attempt, *extended_info = row.next.text.gsub(' ',';').split(/;|: /)
|
654
|
+
when text.length == 6 # service flapping alert
|
655
|
+
last_check, alert_type, host, service, status, state, *extended_info = row.next.text.gsub(' ',';').split(/;|: /)
|
656
|
+
when text.length == 5 # scheduled host downtime
|
657
|
+
last_check, alert_type, host, status, *extended_info = row.next.text.gsub(' ',';').split(/;|: /)
|
658
|
+
end
|
659
|
+
|
660
|
+
service_extinfo_url = service ? "#{extinfo_url}?type=2&host=#{host}&service=#{CGI.escape(service)}" : nil
|
661
|
+
host_extinfo_url = "#{extinfo_url}?type=1&host=#{host}"
|
662
|
+
|
663
|
+
alert = Hashie::Mash.new :last_check => last_check.gsub('[','').gsub(']',''),
|
664
|
+
:alert_type => alert_type,
|
665
|
+
:host => host,
|
666
|
+
:service => service,
|
667
|
+
:status => status,
|
668
|
+
:state => state,
|
669
|
+
:attempt => attempt,
|
670
|
+
:extended_info => extended_info.nil? ? extended_info : extended_info.join(': ').strip,
|
671
|
+
:host_extinfo_url => host_extinfo_url,
|
672
|
+
:service_extinfo_url => service_extinfo_url
|
673
|
+
|
674
|
+
yield alert
|
675
|
+
end
|
676
|
+
end
|
677
|
+
end
|
453
678
|
|
454
679
|
def debug(*args)
|
455
680
|
$stderr.puts *args if ENV['DEBUG']
|