icinga2 0.7.0.1 → 0.8.1.2

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.
@@ -1,9 +1,4 @@
1
-
2
1
  # frozen_string_literal: true
3
- #
4
- #
5
- #
6
- #
7
2
 
8
3
  require 'rest-client'
9
4
  require 'openssl'
@@ -15,7 +10,7 @@ require 'uri'
15
10
  require_relative 'logging'
16
11
  require_relative 'icinga2/version'
17
12
  require_relative 'icinga2/network'
18
- require_relative 'icinga2/status'
13
+ require_relative 'icinga2/statistics'
19
14
  require_relative 'icinga2/converts'
20
15
  require_relative 'icinga2/tools'
21
16
  require_relative 'icinga2/downtimes'
@@ -28,11 +23,20 @@ require_relative 'icinga2/users'
28
23
  require_relative 'icinga2/usergroups'
29
24
 
30
25
  # -------------------------------------------------------------------------------------------------------------------
31
- # Namespace for classes and modules that handle all Icinga2 API calls
26
+ #
27
+ # @abstract # Namespace for classes and modules that handle all Icinga2 API calls
28
+ #
29
+ # @author Bodo Schulz <bodo@boone-schulz.de>
30
+ #
31
+ #
32
32
  module Icinga2
33
33
 
34
34
  # static variable for hosts down
35
- HOSTS_DOWN = 1
35
+ HOSTS_DOWN = 1
36
+ # static variable for hosts critical
37
+ HOSTS_CRITICAL = 2
38
+ # static variable for hosts unknown
39
+ HOSTS_UNKNOWN = 3
36
40
 
37
41
  # static variables for handled warning
38
42
  SERVICE_STATE_WARNING = 1
@@ -48,22 +52,11 @@ module Icinga2
48
52
  #
49
53
  class Client
50
54
 
51
- attr_reader :version, :revision, :node_name, :start_time, :uptime
52
- attr_reader :avg_latency, :avg_execution_time
53
- attr_reader :hosts_up, :hosts_down, :hosts_in_downtime, :hosts_acknowledged
54
- attr_reader :hosts_all, :hosts_problems, :hosts_problems_down, :hosts_handled_warning_problems, :hosts_handled_critical_problems, :hosts_handled_unknown_problems
55
- attr_reader :hosts_handled_problems, :hosts_down_adjusted
56
-
57
- attr_reader :services_ok, :services_warning, :services_critical, :services_unknown, :services_in_downtime, :services_acknowledged
58
- attr_reader :services_all, :services_problems, :services_handled_warning_problems, :services_handled_critical_problems, :services_handled_unknown_problems
59
- attr_reader :services_warning_adjusted, :services_critical_adjusted, :services_unknown_adjusted
60
- attr_reader :hosts_active_checks_1min, :hosts_passive_checks_1min, :services_active_checks_1min, :services_passive_checks_1min
61
-
62
55
  include Logging
63
56
 
64
57
  include Icinga2::Version
65
58
  include Icinga2::Network
66
- include Icinga2::Status
59
+ include Icinga2::Statistics
67
60
  include Icinga2::Converts
68
61
  include Icinga2::Tools
69
62
  include Icinga2::Downtimes
@@ -78,12 +71,13 @@ module Icinga2
78
71
  # Returns a new instance of Client
79
72
  #
80
73
  # @param [Hash, #read] settings the settings for Icinga2
81
- # @option settings [String] :icinga, :host the Icinga2 Hostname (default: 'localhost')
82
- # @option settings [Integer] :icinga, :api, :port the Icinga2 API Port (default: 5665)
83
- # @option settings [String] :icinga, :api, :user the Icinga2 API User
84
- # @option settings [String] :icinga, :api, :password the Icinga2 API Password
85
- # @option settings [Bool] :icinga, :cluster Icinga2 Cluster Mode
86
- # @option settings [Bool] :icinga, :notifications enable Icinga2 Host Notifications (default: false)
74
+ # @option settings [String] :host ('localhost') the Icinga2 Hostname
75
+ # @option settings [Integer] :port (5665) the Icinga2 API Port
76
+ # @option settings [String] :user the Icinga2 API User
77
+ # @option settings [String] :password the Icinga2 API Password
78
+ # @option settings [Integer] :version (1) the Icinga2 API Version
79
+ # @option settings [Bool] :cluster Icinga2 Cluster Mode
80
+ # @option settings [Bool] :notifications (false) enable Icinga2 Host Notifications
87
81
  #
88
82
  # @example to create an new Instance
89
83
  # config = {
@@ -92,7 +86,8 @@ module Icinga2
92
86
  # api: {
93
87
  # port: 5665,
94
88
  # user: 'root',
95
- # password: 'icinga'
89
+ # password: 'icinga',
90
+ # version: 1
96
91
  # },
97
92
  # cluster: false,
98
93
  # satellite: true
@@ -103,70 +98,72 @@ module Icinga2
103
98
  #
104
99
  # @return [instance, #read]
105
100
  #
106
- def initialize( settings = {} )
107
-
108
- @icinga_host = settings.dig(:icinga, :host) || 'localhost'
109
- @icinga_api_port = settings.dig(:icinga, :api, :port) || 5665
110
- @icinga_api_user = settings.dig(:icinga, :api, :user)
111
- @icinga_api_pass = settings.dig(:icinga, :api, :password)
112
- @icinga_api_pki_path = settings.dig(:icinga, :api, :pki_path)
113
- @icinga_api_node_name = settings.dig(:icinga, :api, :node_name)
114
-
115
- @icinga_cluster = settings.dig(:icinga, :cluster) || false
116
- @icinga_satellite = settings.dig(:icinga, :satellite)
117
- @icinga_notifications = settings.dig(:icinga, :notifications) || false
118
-
119
- @icinga_api_url_base = format( 'https://%s:%d', @icinga_host, @icinga_api_port )
120
-
121
- if( @icinga_api_node_name.nil? )
122
- @icinga_api_node_name = Socket.gethostbyname( Socket.gethostname ).first
123
- end
124
-
125
- @has_cert, @options = cert?(
126
- pki_path: @icinga_api_pki_path,
127
- node_name: @icinga_api_node_name,
128
- user: @icinga_api_user,
129
- password: @icinga_api_pass
101
+ def initialize( settings )
102
+
103
+ raise ArgumentError.new('only Hash are allowed') unless( settings.is_a?(Hash) )
104
+ raise ArgumentError.new('missing settings') if( settings.size.zero? )
105
+
106
+ icinga_host = settings.dig(:icinga, :host) || 'localhost'
107
+ icinga_api_port = settings.dig(:icinga, :api, :port) || 5665
108
+ icinga_api_user = settings.dig(:icinga, :api, :user)
109
+ icinga_api_pass = settings.dig(:icinga, :api, :password)
110
+ icinga_api_version = settings.dig(:icinga, :api, :version) || 1
111
+ icinga_api_pki_path = settings.dig(:icinga, :api, :pki_path)
112
+ icinga_api_node_name = settings.dig(:icinga, :api, :node_name)
113
+ @icinga_cluster = settings.dig(:icinga, :cluster) || false
114
+ @icinga_satellite = settings.dig(:icinga, :satellite)
115
+ @icinga_notifications = settings.dig(:icinga, :notifications) || false
116
+
117
+ @icinga_api_url_base = format( 'https://%s:%d/v%s', icinga_host, icinga_api_port, icinga_api_version )
118
+
119
+ _has_cert, @options = cert?(
120
+ pki_path: icinga_api_pki_path,
121
+ node_name: icinga_api_node_name,
122
+ user: icinga_api_user,
123
+ password: icinga_api_pass
130
124
  )
131
125
 
132
126
  @headers = { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
133
127
 
134
-
135
- @version = @revision = 0
136
- @node_name = @start_time = @uptime = ''
137
- @avg_latency = @avg_execution_time = 0
138
- @hosts_up = @hosts_down = @hosts_in_downtime = @hosts_acknowledged = 0
139
- @hosts_all = @hosts_problems = @hosts_handled_warning_problems = @hosts_handled_critical_problems = @hosts_handled_unknown_problems = 0
140
- @hosts_handled_problems = @hosts_down_adjusted = 0
141
- @services_ok = @services_warning = @services_critical = @services_unknown = @services_in_downtime = @services_acknowledged = 0
142
- @services_all = @services_problems = @services_handled_warning_problems = @services_handled_critical_problems = @services_handled_unknown_problems = 0
143
- @services_warning_adjusted = @services_critical_adjusted = @services_unknown_adjusted = 0
144
- @hosts_active_checks_1min = @hosts_passive_checks_1min = @services_active_checks_1min = @services_passive_checks_1min = 0
145
-
146
- extract_data
147
-
148
128
  self
149
129
  end
150
130
 
151
- # @param [Hash, #read] params create a HTTP Header based on a Icinga2 Certificate or an User PAI Login
152
- # @option params [String] :node_name the Icinga2 Hostname (default: 'localhost')
153
- # @option params [Integer] :user the Icinga2 API User
154
- # @option params [Integer] :password the Icinga2 API Password
131
+ # create a HTTP Header based on a Icinga2 Certificate or an User API Login
132
+ #
133
+ # @param [Hash, #read] params
134
+ # @option params [String] :pki_path the location of the Certificate Files
135
+ # @option params [String] :node_name the Icinga2 Hostname
136
+ # @option params [String] :user the Icinga2 API User
137
+ # @option params [String] :password the Icinga2 API Password
138
+ #
155
139
  # @example with Certificate
156
- # @icinga.cert?(pki_path: '/etc/icinga2', name_name: 'icinga2-dashing')
140
+ # @icinga.cert?(pki_path: '/etc/icinga2', node_name: 'icinga2-dashing')
157
141
  #
158
142
  # @example with User
159
143
  # @icinga.cert?(user: 'root', password: 'icinga')
160
144
  #
161
145
  # @return [Bool, #read]
162
146
  #
163
- def cert?( params = {} )
147
+ def cert?( params )
148
+
149
+ raise ArgumentError.new('only Hash are allowed') unless( params.is_a?(Hash) )
150
+ raise ArgumentError.new('missing params') if( params.size.zero? )
164
151
 
165
152
  pki_path = params.dig(:pki_path)
166
153
  node_name = params.dig(:node_name)
167
154
  user = params.dig(:user)
168
155
  password = params.dig(:password)
169
156
 
157
+ if( node_name.nil? )
158
+ begin
159
+ node_name = Socket.gethostbyname(Socket.gethostname).first
160
+ logger.debug(format('node name: %s', node_name))
161
+ rescue SocketError => e
162
+
163
+ raise format("can't resolve hostname (%s)", e)
164
+ end
165
+ end
166
+
170
167
  ssl_cert_file = format( '%s/%s.crt', pki_path, node_name )
171
168
  ssl_key_file = format( '%s/%s.key', pki_path, node_name )
172
169
  ssl_ca_file = format( '%s/ca.crt', pki_path )
@@ -193,6 +190,9 @@ module Icinga2
193
190
 
194
191
  logger.debug( 'PKI not found, using basic auth for connection to Icinga 2 API' )
195
192
 
193
+ raise ArgumentError.new('Missing user_name') if( user.nil? )
194
+ raise ArgumentError.new('Missing password') if( password.nil? )
195
+
196
196
  [false, {
197
197
  user: user,
198
198
  password: password,
@@ -202,6 +202,191 @@ module Icinga2
202
202
 
203
203
  end
204
204
 
205
+
206
+ # return Icinga2 Application data
207
+ #
208
+ # @example
209
+ # @icinga.application_data
210
+ #
211
+ # @return [Hash]
212
+ #
213
+ def application_data
214
+
215
+ data = Network.application_data(
216
+ url: format( '%s/status/IcingaApplication', @icinga_api_url_base ),
217
+ headers: @headers,
218
+ options: @options
219
+ )
220
+
221
+ return nil if( data.nil? )
222
+
223
+ app_data = data.dig('icingaapplication','app')
224
+
225
+ # version and revision
226
+ @version, @revision = parse_version(app_data.dig('version'))
227
+
228
+ # - node_name
229
+ @node_name = app_data.dig('node_name')
230
+
231
+ # - start_time
232
+ @start_time = Time.at(app_data.dig('program_start').to_f)
233
+
234
+ data
235
+ end
236
+
237
+ # return Icinga2 CIB
238
+ #
239
+ # @example
240
+ # @icinga.cib_data
241
+ #
242
+ # @return [Hash]
243
+ #
244
+ def cib_data
245
+
246
+ data = Network.application_data(
247
+ url: format( '%s/status/CIB', @icinga_api_url_base ),
248
+ headers: @headers,
249
+ options: @options
250
+ )
251
+
252
+ unless( data.nil? )
253
+
254
+ cib_data = data.clone
255
+
256
+ # extract
257
+ # - uptime
258
+ uptime = cib_data.dig('uptime').round(2)
259
+ @uptime = Time.at(uptime).utc.strftime('%H:%M:%S')
260
+
261
+ # - avg_latency / avg_execution_time
262
+ @avg_latency = cib_data.dig('avg_latency').round(2)
263
+ @avg_execution_time = cib_data.dig('avg_execution_time').round(2)
264
+
265
+ # - hosts
266
+ @hosts_up = cib_data.dig('num_hosts_up').to_i
267
+ @hosts_down = cib_data.dig('num_hosts_down').to_i
268
+ @hosts_pending = cib_data.dig('num_hosts_pending').to_i
269
+ @hosts_unreachable = cib_data.dig('num_hosts_unreachable').to_i
270
+ @hosts_in_downtime = cib_data.dig('num_hosts_in_downtime').to_i
271
+ @hosts_acknowledged = cib_data.dig('num_hosts_acknowledged').to_i
272
+
273
+ # - services
274
+ @services_ok = cib_data.dig('num_services_ok').to_i
275
+ @services_warning = cib_data.dig('num_services_warning').to_i
276
+ @services_critical = cib_data.dig('num_services_critical').to_i
277
+ @services_unknown = cib_data.dig('num_services_unknown').to_i
278
+ @services_pending = cib_data.dig('num_services_pending').to_i
279
+ @services_in_downtime = cib_data.dig('num_services_in_downtime').to_i
280
+ @services_acknowledged = cib_data.dig('num_services_acknowledged').to_i
281
+
282
+ # - check stats
283
+ @hosts_active_checks_1min = cib_data.dig('active_host_checks_1min')
284
+ @hosts_passive_checks_1min = cib_data.dig('passive_host_checks_1min')
285
+ @services_active_checks_1min = cib_data.dig('active_service_checks_1min')
286
+ @services_passive_checks_1min = cib_data.dig('passive_service_checks_1min')
287
+
288
+ end
289
+
290
+ data
291
+ end
292
+
293
+ # return Icinga2 Status Data
294
+ #
295
+ # @example
296
+ # @icinga.status_data
297
+ #
298
+ # @return [Hash]
299
+ #
300
+ def status_data
301
+
302
+ Network.application_data(
303
+ url: format( '%s/status', @icinga_api_url_base ),
304
+ headers: @headers,
305
+ options: @options
306
+ )
307
+ end
308
+
309
+ # return Icinga2 API Listener
310
+ #
311
+ # @example
312
+ # @icinga.api_listener
313
+ #
314
+ # @return [Hash]
315
+ #
316
+ def api_listener
317
+
318
+ Network.application_data(
319
+ url: format( '%s/status/ApiListener', @icinga_api_url_base ),
320
+ headers: @headers,
321
+ options: @options
322
+ )
323
+ end
324
+
325
+ # return Icinga2 version and revision
326
+ #
327
+ # @example
328
+ # @icinga.application_data
329
+ # @icinga.version.values
330
+ #
331
+ # v = @icinga.version
332
+ # version = v.dig(:version)
333
+ #
334
+ # @return [Hash]
335
+ # * version
336
+ # * revision
337
+ #
338
+ def version
339
+ version = @version.nil? ? 0 : @version
340
+ revision = @revision.nil? ? 0 : @revision
341
+
342
+ {
343
+ version: version.to_s,
344
+ revision: revision.to_s
345
+ }
346
+ end
347
+
348
+ # return Icinga2 node_name
349
+ #
350
+ # @example
351
+ # @icinga.application_data
352
+ # @icinga.node_name
353
+ #
354
+ # @return [String]
355
+ #
356
+ def node_name
357
+ return @node_name if( @node_name )
358
+
359
+ nil
360
+ end
361
+
362
+ # return Icinga2 start time
363
+ #
364
+ # @example
365
+ # @icinga.application_data
366
+ # @icinga.start_time
367
+ #
368
+ # @return [String]
369
+ #
370
+ def start_time
371
+ return @start_time if( @start_time )
372
+
373
+ nil
374
+ end
375
+
376
+ # return Icinga2 uptime
377
+ #
378
+ # @example
379
+ # @icinga.cib_data
380
+ # @icinga.uptime
381
+ #
382
+ # @return [String]
383
+ #
384
+ def uptime
385
+ return @uptime if( @uptime )
386
+
387
+ nil
388
+ end
389
+
205
390
  end
206
391
  end
207
392
 
@@ -11,9 +11,10 @@ module Icinga2
11
11
  # convert a Icinga2 state into a human readable state
12
12
  #
13
13
  # @param [String] state the Icinga2 State
14
- # @param [Bool] is_host if this a Host or a Service Check
14
+ # @param [Bool] is_host (false) if this a Host or a Service Check
15
15
  #
16
16
  # @return [String]
17
+ #
17
18
  def self.state_to_string( state, is_host = false )
18
19
 
19
20
  state =
@@ -46,9 +47,10 @@ module Icinga2
46
47
  # convert a Icinga2 state into a named color
47
48
  #
48
49
  # @param [String] state the Icinga2 State
49
- # @param [Bool] is_host if this a Host or a Service Check
50
+ # @param [Bool] is_host (false) if this a Host or a Service Check
50
51
  #
51
52
  # @return [String]
53
+ #
52
54
  def self.state_to_color( state, is_host = false )
53
55
 
54
56
  state =
@@ -83,6 +85,7 @@ module Icinga2
83
85
  # @param [String] name
84
86
  #
85
87
  # @return [String]
88
+ #
86
89
  def self.format_service( name )
87
90
  service_map = name.split('!', 2)
88
91
  service_map.join( ' - ' )
@@ -32,7 +32,10 @@ module Icinga2
32
32
  #
33
33
  # @return [Hash]
34
34
  #
35
- def add_downtime( params = {} )
35
+ def add_downtime( params )
36
+
37
+ raise ArgumentError.new('only Hash are allowed') unless( params.is_a?(Hash) )
38
+ raise ArgumentError.new('missing params') if( params.size.zero? )
36
39
 
37
40
  name = params.dig(:name)
38
41
  host_name = params.dig(:host)
@@ -46,29 +49,14 @@ module Icinga2
46
49
 
47
50
  # sanitychecks
48
51
  #
49
- if( name.nil? )
50
- return {
51
- status: 404,
52
- message: 'missing downtime name'
53
- }
54
- end
55
-
56
- if( %w[host service].include?(type.downcase) == false )
57
- return {
58
- status: 404,
59
- message: "wrong downtype type. only 'host' or' service' allowed ('#{type}' giving"
60
- }
61
- else
62
- # we need the first char as Uppercase
63
- type = type.capitalize
64
- end
65
-
66
- if( !host_group.nil? && !host_name.nil? )
67
- return {
68
- status: 404,
69
- message: 'choose host or host_group, not both'
70
- }
71
- end
52
+ raise ArgumentError.new('Missing name') if( name.nil? )
53
+ raise ArgumentError.new("wrong downtype type. only 'host' or' service' allowed ('#{type}' giving)") if( %w[host service].include?(type.downcase) == false )
54
+ raise ArgumentError.new('choose host or host_group, not both') if( !host_group.nil? && !host_name.nil? )
55
+ raise ArgumentError.new('Missing downtime author') if( author.nil? )
56
+ raise ArgumentError.new("these author ar not exists: #{author}") unless( exists_user?( author ) )
57
+ raise ArgumentError.new('Missing downtime comment') if( comment.nil? )
58
+ raise ArgumentError.new('Missing downtime end_time') if( end_time.nil? )
59
+ raise ArgumentError.new('end_time are equal or smaller then start_time') if( end_time.to_i <= start_time )
72
60
 
73
61
  if( !host_name.nil? )
74
62
 
@@ -78,47 +66,10 @@ module Icinga2
78
66
  # check if hostgroup available ?
79
67
  #
80
68
  filter = format( '"%s" in host.groups', host_group )
81
- else
82
-
83
- return {
84
- status: 404,
85
- message: 'missing host or host_group for downtime'
86
- }
87
- end
88
-
89
- if( comment.nil? )
90
- return {
91
- status: 404,
92
- message: 'missing downtime comment'
93
- }
94
- end
95
-
96
- if( author.nil? )
97
- return {
98
- status: 404,
99
- message: 'missing downtime author'
100
- }
101
- elsif( exists_user?( author ) == false )
102
- return {
103
- status: 404,
104
- message: "these author ar not exists: #{author}"
105
- }
106
- end
107
-
108
- if( end_time.nil? )
109
- return {
110
- status: 404,
111
- message: 'missing end_time'
112
- }
113
- elsif( end_time.to_i <= start_time )
114
- return {
115
- status: 404,
116
- message: 'end_time are equal or smaller then start_time'
117
- }
118
69
  end
119
70
 
120
71
  payload = {
121
- 'type' => type,
72
+ 'type' => type.capitalize, # we need the first char as Uppercase
122
73
  'start_time' => start_time,
123
74
  'end_time' => end_time,
124
75
  'author' => author,
@@ -128,45 +79,32 @@ module Icinga2
128
79
  'filter' => filter
129
80
  }
130
81
 
131
- Network.post( host: name,
132
- url: format( '%s/v1/actions/schedule-downtime', @icinga_api_url_base ),
82
+ Network.post(
83
+ url: format( '%s/actions/schedule-downtime', @icinga_api_url_base ),
133
84
  headers: @headers,
134
85
  options: @options,
135
- payload: payload )
136
-
137
-
138
- # schedule downtime for a host
139
- # --data '{ "type": "Host", "filter": "host.name==\"api_dummy_host_1\"", ... }'
140
-
141
- # schedule downtime for all services of a host
142
- # --data '{ "type": "Service", "filter": "host.name==\"api_dummy_host_1\"", ... }'
143
-
144
- # schedule downtime for all hosts and services in a hostgroup
145
- # --data '{ "type": "Host", "filter": "\"api_dummy_hostgroup\" in host.groups", ... }'
146
-
147
- # --data '{ "type": "Service", "filter": "\"api_dummy_hostgroup\" in host.groups)", ... }'
148
-
86
+ payload: payload
87
+ )
149
88
  end
150
89
 
151
90
  # return downtimes
152
91
  #
153
- # @param [Hash] params
154
- # @option params [String] :host
155
- #
156
92
  # @example
157
93
  # @icinga.downtimes
158
94
  #
159
- # @return [Hash]
95
+ # @return [Array]
160
96
  #
161
- def downtimes( params = {} )
162
-
163
- host = params.dig(:host)
97
+ def downtimes
164
98
 
165
- Network.get( host: host,
166
- url: format( '%s/v1/objects/downtimes/%s', @icinga_api_url_base, host ),
99
+ data = Network.api_data(
100
+ url: format( '%s/objects/downtimes' , @icinga_api_url_base ),
167
101
  headers: @headers,
168
- options: @options )
102
+ options: @options
103
+ )
104
+
105
+ return data.dig('results') if( data.dig(:status).nil? )
169
106
 
107
+ nil
170
108
  end
171
109
 
172
110
  end