icinga2 0.5.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.
- checksums.yaml +7 -0
- data/LICENSE +504 -0
- data/README.md +118 -0
- data/doc/downtimes.md +7 -0
- data/doc/examples +122 -0
- data/doc/hostgroups.md +19 -0
- data/doc/hosts.md +22 -0
- data/doc/notifications.md +15 -0
- data/doc/servicegroups.md +19 -0
- data/doc/services.md +26 -0
- data/doc/usergroups.md +12 -0
- data/doc/users.md +41 -0
- data/examples/test.rb +150 -0
- data/lib/icinga2.rb +140 -0
- data/lib/icinga2/converts.rb +77 -0
- data/lib/icinga2/downtimes.rb +173 -0
- data/lib/icinga2/hostgroups.rb +98 -0
- data/lib/icinga2/hosts.rb +307 -0
- data/lib/icinga2/network.rb +397 -0
- data/lib/icinga2/notifications.rb +158 -0
- data/lib/icinga2/servicegroups.rb +101 -0
- data/lib/icinga2/services.rb +301 -0
- data/lib/icinga2/status.rb +52 -0
- data/lib/icinga2/tools.rb +13 -0
- data/lib/icinga2/usergroups.rb +101 -0
- data/lib/icinga2/users.rb +143 -0
- data/lib/icinga2/version.rb +15 -0
- data/lib/logging.rb +36 -0
- metadata +210 -0
data/lib/icinga2.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'rest-client'
|
8
|
+
require 'openssl'
|
9
|
+
|
10
|
+
require 'json'
|
11
|
+
require 'net/http'
|
12
|
+
require 'uri'
|
13
|
+
|
14
|
+
require_relative 'logging'
|
15
|
+
require_relative 'icinga2/version'
|
16
|
+
require_relative 'icinga2/network'
|
17
|
+
require_relative 'icinga2/status'
|
18
|
+
require_relative 'icinga2/converts'
|
19
|
+
require_relative 'icinga2/tools'
|
20
|
+
require_relative 'icinga2/downtimes'
|
21
|
+
require_relative 'icinga2/notifications'
|
22
|
+
require_relative 'icinga2/hosts'
|
23
|
+
require_relative 'icinga2/hostgroups'
|
24
|
+
require_relative 'icinga2/services'
|
25
|
+
require_relative 'icinga2/servicegroups'
|
26
|
+
require_relative 'icinga2/users'
|
27
|
+
require_relative 'icinga2/usergroups'
|
28
|
+
|
29
|
+
# -------------------------------------------------------------------------------------------------------------------
|
30
|
+
|
31
|
+
module Icinga2
|
32
|
+
|
33
|
+
class Client
|
34
|
+
|
35
|
+
include Logging
|
36
|
+
|
37
|
+
include Icinga2::Version
|
38
|
+
include Icinga2::Network
|
39
|
+
include Icinga2::Status
|
40
|
+
include Icinga2::Converts
|
41
|
+
include Icinga2::Tools
|
42
|
+
include Icinga2::Downtimes
|
43
|
+
include Icinga2::Notifications
|
44
|
+
include Icinga2::Hosts
|
45
|
+
include Icinga2::Hostgroups
|
46
|
+
include Icinga2::Services
|
47
|
+
include Icinga2::Servicegroups
|
48
|
+
include Icinga2::Users
|
49
|
+
include Icinga2::Usergroups
|
50
|
+
|
51
|
+
|
52
|
+
def initialize( settings = {} )
|
53
|
+
|
54
|
+
@icingaHost = settings.dig(:icinga, :host) || 'localhost'
|
55
|
+
@icingaApiPort = settings.dig(:icinga, :api, :port) || 5665
|
56
|
+
@icingaApiUser = settings.dig(:icinga, :api, :user)
|
57
|
+
@icingaApiPass = settings.dig(:icinga, :api, :password)
|
58
|
+
@icingaCluster = settings.dig(:icinga, :cluster) || false
|
59
|
+
@icingaSatellite = settings.dig(:icinga, :satellite)
|
60
|
+
@icingaNotifications = settings.dig(:icinga, :notifications) || false
|
61
|
+
|
62
|
+
@icingaApiUrlBase = sprintf( 'https://%s:%d', @icingaHost, @icingaApiPort )
|
63
|
+
@nodeName = Socket.gethostbyname( Socket.gethostname ).first
|
64
|
+
|
65
|
+
date = '2017-06-08'
|
66
|
+
|
67
|
+
logger.info( '-----------------------------------------------------------------' )
|
68
|
+
logger.info( ' Icinga2 Management' )
|
69
|
+
logger.info( " Version #{VERSION} (#{date})" )
|
70
|
+
logger.info( ' Copyright 2016-2017 Bodo Schulz' )
|
71
|
+
logger.info( " Backendsystem #{@icingaApiUrlBase}" )
|
72
|
+
logger.info( sprintf( ' cluster enabled: %s', @icingaCluster ? 'true' : 'false' ) )
|
73
|
+
logger.info( sprintf( ' notifications enabled: %s', @icingaNotifications ? 'true' : 'false' ) )
|
74
|
+
if( @icingaCluster )
|
75
|
+
logger.info( sprintf( ' satellite endpoint: %s', @icingaSatellite ) )
|
76
|
+
end
|
77
|
+
logger.info( '-----------------------------------------------------------------' )
|
78
|
+
logger.info( '' )
|
79
|
+
|
80
|
+
logger.debug( sprintf( ' server : %s', @icingaHost ) )
|
81
|
+
logger.debug( sprintf( ' port : %s', @icingaApiPort ) )
|
82
|
+
logger.debug( sprintf( ' api url : %s', @icingaApiUrlBase ) )
|
83
|
+
logger.debug( sprintf( ' api user : %s', @icingaApiUser ) )
|
84
|
+
logger.debug( sprintf( ' api pass : %s', @icingaApiPass ) )
|
85
|
+
logger.debug( sprintf( ' node name: %s', @nodeName ) )
|
86
|
+
|
87
|
+
@hasCert = self.checkCert( { :user => @icingaApiUser, :password => @icingaApiPass } )
|
88
|
+
@headers = { "Content-Type" => "application/json", "Accept" => "application/json" }
|
89
|
+
|
90
|
+
return self
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def checkCert( params = {} )
|
96
|
+
|
97
|
+
nodeName = params.dig(:nodeName) || 'localhost'
|
98
|
+
|
99
|
+
user = params.dig(:user) || 'admin'
|
100
|
+
password = params.dig(:password) || ''
|
101
|
+
|
102
|
+
# check whether pki files are there, otherwise use basic auth
|
103
|
+
if File.file?( sprintf( 'pki/%s.crt', nodeName ) )
|
104
|
+
|
105
|
+
logger.debug( "PKI found, using client certificates for connection to Icinga 2 API" )
|
106
|
+
|
107
|
+
sslCertFile = File.read( sprintf( 'pki/%s.crt', nodeName ) )
|
108
|
+
sslKeyFile = File.read( sprintf( 'pki/%s.key', nodeName ) )
|
109
|
+
sslCAFile = File.read( 'pki/ca.crt' )
|
110
|
+
|
111
|
+
cert = OpenSSL::X509::Certificate.new( sslCertFile )
|
112
|
+
key = OpenSSL::PKey::RSA.new( sslKeyFile )
|
113
|
+
|
114
|
+
@options = {
|
115
|
+
:ssl_client_cert => cert,
|
116
|
+
:ssl_client_key => key,
|
117
|
+
:ssl_ca_file => sslCAFile,
|
118
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_NONE
|
119
|
+
}
|
120
|
+
|
121
|
+
return true
|
122
|
+
else
|
123
|
+
|
124
|
+
logger.debug( "PKI not found, using basic auth for connection to Icinga 2 API" )
|
125
|
+
|
126
|
+
@options = {
|
127
|
+
:user => user,
|
128
|
+
:password => password,
|
129
|
+
:verify_ssl => OpenSSL::SSL::VERIFY_NONE
|
130
|
+
}
|
131
|
+
|
132
|
+
return false
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# EOF
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Icinga2
|
4
|
+
|
5
|
+
module Converts
|
6
|
+
|
7
|
+
def self.stateToString( state, is_host = false )
|
8
|
+
|
9
|
+
if( is_host == true )
|
10
|
+
|
11
|
+
state = case state
|
12
|
+
when 0
|
13
|
+
'Up'
|
14
|
+
when 1
|
15
|
+
'Down'
|
16
|
+
else
|
17
|
+
'Undefined'
|
18
|
+
end
|
19
|
+
else
|
20
|
+
|
21
|
+
state = case state
|
22
|
+
when 0
|
23
|
+
'OK'
|
24
|
+
when 1
|
25
|
+
'Warning'
|
26
|
+
when 2
|
27
|
+
'Critical'
|
28
|
+
when 3
|
29
|
+
'Unknown'
|
30
|
+
else
|
31
|
+
'Undefined'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
return state
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.stateToColor( state, is_host = false )
|
40
|
+
|
41
|
+
if( is_host == true )
|
42
|
+
|
43
|
+
state = case state
|
44
|
+
when 0
|
45
|
+
'green'
|
46
|
+
when 1
|
47
|
+
'red'
|
48
|
+
else
|
49
|
+
'blue'
|
50
|
+
end
|
51
|
+
else
|
52
|
+
|
53
|
+
state = case state
|
54
|
+
when 0
|
55
|
+
'green'
|
56
|
+
when 1
|
57
|
+
'yellow'
|
58
|
+
when 2
|
59
|
+
'red'
|
60
|
+
when 3
|
61
|
+
'purple'
|
62
|
+
else
|
63
|
+
'blue'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
return state
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.formatService( name )
|
71
|
+
service_map = name.split('!', 2)
|
72
|
+
service_map.join( ' - ' )
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
|
2
|
+
module Icinga2
|
3
|
+
|
4
|
+
module Downtimes
|
5
|
+
|
6
|
+
|
7
|
+
def addDowntime( params = {} )
|
8
|
+
|
9
|
+
name = params.dig(:name)
|
10
|
+
hostName = params.dig(:host)
|
11
|
+
# serviceName = params.dig(:service)
|
12
|
+
hostGroup = params.dig(:host_group)
|
13
|
+
startTime = params.dig(:start_time) || Time.now.to_i
|
14
|
+
endTime = params.dig(:end_time)
|
15
|
+
author = params.dig(:author)
|
16
|
+
comment = params.dig(:comment)
|
17
|
+
type = params.dig(:type)
|
18
|
+
filter = nil
|
19
|
+
|
20
|
+
# sanitychecks
|
21
|
+
#
|
22
|
+
if( name == nil )
|
23
|
+
|
24
|
+
return {
|
25
|
+
:status => 404,
|
26
|
+
:message => 'missing downtime name'
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
if( ['host','service'].include?(type.downcase) == false )
|
31
|
+
|
32
|
+
return {
|
33
|
+
:status => 404,
|
34
|
+
:message => "wrong downtype type. only 'host' or' service' allowed ('#{type}' giving"
|
35
|
+
}
|
36
|
+
else
|
37
|
+
# we need the first char as Uppercase
|
38
|
+
type.capitalize!
|
39
|
+
end
|
40
|
+
|
41
|
+
if( hostGroup != nil && hostName != nil )
|
42
|
+
|
43
|
+
return {
|
44
|
+
:status => 404,
|
45
|
+
:message => 'choose host or host_group, not both'
|
46
|
+
}
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
if( hostName != nil )
|
51
|
+
|
52
|
+
filter = sprintf( 'host.name=="%s"', hostName )
|
53
|
+
elsif( hostGroup != nil )
|
54
|
+
|
55
|
+
# check if hostgroup available ?
|
56
|
+
#
|
57
|
+
filter = sprintf( '"%s" in host.groups', hostGroup )
|
58
|
+
else
|
59
|
+
|
60
|
+
return {
|
61
|
+
:status => 404,
|
62
|
+
:message => 'missing host or host_group for downtime'
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
if( comment == nil )
|
67
|
+
|
68
|
+
return {
|
69
|
+
:status => 404,
|
70
|
+
:message => 'missing downtime comment'
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
if( author == nil )
|
75
|
+
|
76
|
+
return {
|
77
|
+
:status => 404,
|
78
|
+
:message => 'missing downtime author'
|
79
|
+
}
|
80
|
+
else
|
81
|
+
|
82
|
+
if( self.existsUser?( author ) == false )
|
83
|
+
|
84
|
+
return {
|
85
|
+
:status => 404,
|
86
|
+
:message => "these author ar not exists: #{author}"
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
if( endTime == nil )
|
93
|
+
|
94
|
+
return {
|
95
|
+
:status => 404,
|
96
|
+
:message => 'missing end_time'
|
97
|
+
}
|
98
|
+
else
|
99
|
+
|
100
|
+
if( endTime.to_i <= startTime )
|
101
|
+
|
102
|
+
return {
|
103
|
+
:status => 404,
|
104
|
+
:message => 'end_time are equal or smaller then start_time'
|
105
|
+
}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# logger.debug( Time.at( startTime ).strftime( '%Y-%m-%d %H:%M:%S' ) )
|
110
|
+
# logger.debug( Time.at( endTime ).strftime( '%Y-%m-%d %H:%M:%S' ) )
|
111
|
+
|
112
|
+
payload = {
|
113
|
+
"type" => type,
|
114
|
+
"start_time" => startTime,
|
115
|
+
"end_time" => endTime,
|
116
|
+
"author" => author,
|
117
|
+
"comment" => comment,
|
118
|
+
"fixed" => true,
|
119
|
+
"duration" => 30,
|
120
|
+
"filter" => filter
|
121
|
+
}
|
122
|
+
|
123
|
+
# logger.debug( JSON.pretty_generate( payload ) )
|
124
|
+
|
125
|
+
result = Network.post( {
|
126
|
+
:host => name,
|
127
|
+
:url => sprintf( '%s/v1/actions/schedule-downtime', @icingaApiUrlBase ),
|
128
|
+
:headers => @headers,
|
129
|
+
:options => @options,
|
130
|
+
:payload => payload
|
131
|
+
} )
|
132
|
+
|
133
|
+
logger.debug( result.class.to_s )
|
134
|
+
|
135
|
+
return JSON.pretty_generate( result )
|
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
|
+
|
149
|
+
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
def listDowntimes( params = {} )
|
155
|
+
|
156
|
+
name = params.dig(:name)
|
157
|
+
|
158
|
+
result = Network.get( {
|
159
|
+
:host => name,
|
160
|
+
:url => sprintf( '%s/v1/objects/downtimes/%s', @icingaApiUrlBase, name ),
|
161
|
+
:headers => @headers,
|
162
|
+
:options => @options
|
163
|
+
} )
|
164
|
+
|
165
|
+
return JSON.pretty_generate( result )
|
166
|
+
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
module Icinga2
|
3
|
+
|
4
|
+
module Hostgroups
|
5
|
+
|
6
|
+
def addHostgroup( params = {} )
|
7
|
+
|
8
|
+
name = params.dig(:name)
|
9
|
+
displayName = params.dig(:display_name)
|
10
|
+
|
11
|
+
if( name == nil )
|
12
|
+
|
13
|
+
return {
|
14
|
+
:status => 404,
|
15
|
+
:message => 'no name for the hostgroup'
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
payload = {
|
20
|
+
"attrs" => {
|
21
|
+
"display_name" => displayName
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
result = Network.put( {
|
26
|
+
:url => sprintf( '%s/v1/objects/hostgroups/%s', @icingaApiUrlBase, name ),
|
27
|
+
:headers => @headers,
|
28
|
+
:options => @options,
|
29
|
+
:payload => payload
|
30
|
+
} )
|
31
|
+
|
32
|
+
return JSON.pretty_generate( result )
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def deleteHostgroup( params = {} )
|
38
|
+
|
39
|
+
name = params.dig(:name)
|
40
|
+
|
41
|
+
if( name == nil )
|
42
|
+
|
43
|
+
return {
|
44
|
+
:status => 404,
|
45
|
+
:message => 'no name for the hostgroup'
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
result = Network.delete( {
|
50
|
+
:host => name,
|
51
|
+
:url => sprintf( '%s/v1/objects/hostgroups/%s?cascade=1', @icingaApiUrlBase, name ),
|
52
|
+
:headers => @headers,
|
53
|
+
:options => @options
|
54
|
+
} )
|
55
|
+
|
56
|
+
return JSON.pretty_generate( result )
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def listHostgroups( params = {} )
|
62
|
+
|
63
|
+
name = params.dig(:name)
|
64
|
+
|
65
|
+
result = Network.get( {
|
66
|
+
:host => name,
|
67
|
+
:url => sprintf( '%s/v1/objects/hostgroups/%s', @icingaApiUrlBase, name ),
|
68
|
+
:headers => @headers,
|
69
|
+
:options => @options
|
70
|
+
} )
|
71
|
+
|
72
|
+
return JSON.pretty_generate( result )
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def existsHostgroup?( name )
|
78
|
+
|
79
|
+
result = self.listHostgroups( { :name => name } )
|
80
|
+
|
81
|
+
if( result.is_a?( String ) )
|
82
|
+
result = JSON.parse( result )
|
83
|
+
end
|
84
|
+
|
85
|
+
status = result.dig('status')
|
86
|
+
|
87
|
+
if( status != nil && status == 200 )
|
88
|
+
return true
|
89
|
+
end
|
90
|
+
|
91
|
+
return false
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|