zapix3 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8aa4133a57fb5985c634605bbf7de7635d9c43e7
4
+ data.tar.gz: cec3c21554e7c9b9f35c97f795da6336c5e64da6
5
+ SHA512:
6
+ metadata.gz: 7509a1b559da79453b163f57a956531bd14788f3bfd6de65b9b6326b262a60576d4fe53e07967ffdacf52007d56f844793a261ce52552d39821e0fd0703eb602
7
+ data.tar.gz: e323d830d53c6cb8d299ad77dc70b86826e89bc87ca2bfe96c2d1c4d01a9f7b4e66906d0a44ac9dfd610d6f3955cfcc6b67e4dda01e07cfa330720ae7808a402
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zapix.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ zapix3 (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (4.2.6)
10
+ activesupport (= 4.2.6)
11
+ builder (~> 3.1)
12
+ activerecord (4.2.6)
13
+ activemodel (= 4.2.6)
14
+ activesupport (= 4.2.6)
15
+ arel (~> 6.0)
16
+ activesupport (4.2.6)
17
+ i18n (~> 0.7)
18
+ json (~> 1.7, >= 1.7.7)
19
+ minitest (~> 5.1)
20
+ thread_safe (~> 0.3, >= 0.3.4)
21
+ tzinfo (~> 1.1)
22
+ arel (6.0.3)
23
+ builder (3.2.2)
24
+ diff-lcs (1.2.5)
25
+ i18n (0.7.0)
26
+ json (1.8.3)
27
+ minitest (5.9.0)
28
+ rake (11.1.2)
29
+ rspec (3.4.0)
30
+ rspec-core (~> 3.4.0)
31
+ rspec-expectations (~> 3.4.0)
32
+ rspec-mocks (~> 3.4.0)
33
+ rspec-core (3.4.4)
34
+ rspec-support (~> 3.4.0)
35
+ rspec-expectations (3.4.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.4.0)
38
+ rspec-mocks (3.4.1)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.4.0)
41
+ rspec-support (3.4.1)
42
+ thread_safe (0.3.5)
43
+ tzinfo (1.2.2)
44
+ thread_safe (~> 0.1)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ activerecord
51
+ bundler (~> 1.3)
52
+ json
53
+ rake
54
+ rspec
55
+ zapix3!
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Stoyan Stoyanov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,383 @@
1
+ # Zapix3
2
+
3
+ Zapix is a tool which makes the communication with the zabbix's api simple.
4
+
5
+ If you need a more detailed information of how to use zapix see the specs.
6
+
7
+ This version of zappix is compatible with zabbix 3.0
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'zapix', '0.1.0'
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it with gem:
20
+
21
+ $ gem install zapix3
22
+
23
+ ## Usage
24
+
25
+ ### Remote client
26
+ First create a remote client. Feel free to
27
+ disable the debug mode if you find it annoying.
28
+
29
+ ```ruby
30
+ require 'zapix'
31
+ zrc = ZabbixAPI.connect(
32
+ :service_url => 'https://zabbix-server.foo/api_jsonrpc.php',
33
+ :username => 'guybrush',
34
+ :password => 'threepwood',
35
+ :debug => true
36
+ )
37
+ ```
38
+
39
+ ## Functionality
40
+
41
+ ### Hostgroup Operations
42
+ #### Creating a hostgroup
43
+ ```ruby
44
+ zrc.hostgroups.create('test_hostgroup')
45
+ ```
46
+
47
+ #### Checking if a hostgroup exists
48
+ ```ruby
49
+ zrc.hostgroups.exists?('test_hostgroup')
50
+ ```
51
+
52
+ #### Checking if a hostgroup has any attached hosts
53
+ ```ruby
54
+ zrc.hostgroups.any_hosts?('test_hostgroup')
55
+ ```
56
+
57
+ #### Getting all host ids of hosts belonging to a hostgroup
58
+ ```ruby
59
+ zrc.hostgroups.get_host_ids_of('test_hostgroup')
60
+ ```
61
+
62
+ #### Deleting a hostgroup
63
+ Note that deleting a hostgroups with attached hosts also deletes the hosts.
64
+
65
+ ```ruby
66
+ zrc.hostgroups.delete('test_hostgroup')
67
+ ```
68
+
69
+ #### Getting the id of a hostgroup
70
+ ```ruby
71
+ zrc.hostgroups.get_id('test_hostgroup')
72
+ ```
73
+
74
+ #### Getting all hostgroups names
75
+ ```ruby
76
+ zrc.hostgroups.get_all
77
+ ```
78
+
79
+ ### Host Operations
80
+
81
+ #### Getting the id of a host
82
+ ```ruby
83
+ zrc.hosts.get_id('test_host')
84
+ ```
85
+
86
+ #### Checking if a host exists
87
+ ```ruby
88
+ zrc.hosts.exists?('test_host')
89
+ ```
90
+
91
+ #### Getting all host names
92
+ ```ruby
93
+ zrc.hosts.get_all
94
+ ```
95
+
96
+ #### Creating a host
97
+ Note that in zabbix host cannot exists on its own, it always needs a hostgroup.
98
+ ```ruby
99
+ hostgroup_id = zrc.hostgroups.get_id('test_hostgroup')
100
+
101
+ zabbix_interface = Interface.new(
102
+ 'ip' => '127.0.0.1',
103
+ 'dns' => 'abrakadabra.com'
104
+ )
105
+
106
+ jmx_interface = Interface.new(
107
+ 'ip' => '127.0.0.1',
108
+ 'dns' => 'abrakadabra.com',
109
+ 'type' => 4, # JMX
110
+ 'main' => 1, # default jmx interface
111
+ 'port' => 9003
112
+ )
113
+
114
+ template_1 = zrc.templates.get_id('example_template_1')
115
+ template_2 = zrc.templates.get_id('example_template_2')
116
+
117
+ example_host = Host.new
118
+ example_host.add_name('test_host')
119
+ example_host.add_interfaces(zabbix_interface.to_hash)
120
+ example_host.add_interfaces(jmx_interface.to_hash)
121
+ example_host.add_macros({'macro' => '{$TESTMACRO}', 'value' => 'test123'})
122
+ example_host.add_group_ids(hostgroup_id)
123
+ example_host.add_template_ids(template_1, template_2)
124
+ zrc.hosts.create(example_host.to_hash)
125
+ ```
126
+
127
+ #### Deleting a host
128
+ ```ruby
129
+ zrc.hosts.delete('test_host')
130
+ ```
131
+
132
+ ### Template Operations
133
+
134
+ #### Checking if a template exists
135
+ ```ruby
136
+ zrc.templates.exists?('test_template')
137
+ ```
138
+
139
+ #### Getting the id of a template
140
+ ```ruby
141
+ zrc.templates.get_id('test_template')
142
+ ```
143
+
144
+ #### Getting all templates for a host
145
+ ```ruby
146
+ zrc.templates.get_templates_for_host(zrc.hosts.get_id('test_host'))
147
+ ```
148
+
149
+ ### Application Operations
150
+
151
+ #### Getting the id of an application
152
+ Note that an application always belogs to a host.
153
+ ```ruby
154
+ zrc.applications.get_id({
155
+ 'name' => 'test_app',
156
+ 'hostid' => zrc.hosts.get_id('test_name')
157
+ })
158
+ ```
159
+
160
+ #### Creating an application for host
161
+ ```ruby
162
+ zrc.applications.create({
163
+ 'name' => 'test_application'
164
+ 'hostid' => zrc.hosts.get_id('test_host')
165
+ })
166
+ ```
167
+
168
+ ### Web Scenario Operations
169
+ Note that a web scenario needs a host and an application in zabbix 2.0.6. This is
170
+ going to change in the next versions of zabbix. When creating scenarios it also
171
+ makes sense to create triggers for them.
172
+
173
+ #### Checking if a scenario exists
174
+ ```ruby
175
+ zrc.scenarios.exists?({
176
+ 'name' => 'test_scenario',
177
+ 'hostid' => zrc.hosts.get_id('test_host')
178
+ })
179
+ ```
180
+
181
+ #### Getting the id of a scenario
182
+ ```ruby
183
+ zrc.scenarios.get_id({
184
+ 'name' => 'test_scenario'
185
+ 'hostid' => zrc.hosts.get_id('test_host')
186
+ })
187
+ ```
188
+
189
+ #### Creating a scenario
190
+ ```ruby
191
+
192
+ zrc.applications.create({
193
+ 'name' => 'test_app',
194
+ 'hostid' => zrc.hosts.get_id('test_name')
195
+ })
196
+
197
+ webcheck_options = Hash.new
198
+ webcheck_options['hostid'] = zrc.hosts.get_id('host')
199
+ webcheck_options['name'] = 'my first scenario'
200
+ webcheck_options['applicationid'] = zrc.applications.get_id('test_app')
201
+ webcheck_options['steps'] = [{'name' => 'Homepage', 'url' => 'm.test.de', 'status_codes' => 200, 'no' => 1}]
202
+ zrc.scenarios.create(webcheck_options)
203
+ ```
204
+
205
+ #### Deleting a scenario
206
+ ```ruby
207
+ zrc.scenarios.delete({
208
+ 'name' => 'test_scenario',
209
+ 'hostid' => zrc.hosts.get_id('test_host')
210
+ })
211
+ ```
212
+
213
+ ### Trigger Operations
214
+
215
+ #### Checking if a trigger exists
216
+ ```ruby
217
+ zrc.triggers.exists?({
218
+ 'expression' => "{test_host:web.test.fail[test_scenario].max(#3)}#0"
219
+ })
220
+ ```
221
+
222
+ ### Getting the id of a trigger
223
+ ```ruby
224
+ zrc.triggers.get_id({
225
+ 'expression' => "{test_host:web.test.fail[test_scenario].max(#3)}#0"
226
+ })
227
+ ```
228
+
229
+ ### Creating a trigger
230
+ ```ruby
231
+ options = Hash.new
232
+ options['description'] = 'Webpage failed on {HOST.NAME}'
233
+ options['expression'] = "{test_host:web.test.fail[test_scenario].max(#3)}#0"
234
+ options['priority'] = 2 # 2 means Warning
235
+ zrc.triggers.create(options)
236
+ ```
237
+
238
+ ### Deleting a trigger
239
+ ```ruby
240
+ trigger_id = zrc.triggers.get_id({
241
+ 'expression' => "{test_host:web.test.fail[test_scenario].max(#3)}#0"
242
+ })
243
+
244
+ zrc.triggers.delete(trigger_id)
245
+ ```
246
+
247
+ ### Usergroups Operations
248
+
249
+ #### Checking if a usergroup exists
250
+ ```ruby
251
+ zrc.usergroups.exists?({
252
+ 'name' => 'test_usergroup'
253
+ })
254
+ ```
255
+ #### Geting the id of a usergroup
256
+ ```ruby
257
+ zrc.usergroups.get_id({
258
+ 'name' = 'test_usergroup'
259
+ })
260
+ ```
261
+
262
+ #### Creating a usergroup
263
+ ```ruby
264
+ options = Hash.new
265
+ options['name'] = 'test_usergroup'
266
+ options['rights'] = {
267
+ 'permission' => 3,
268
+ 'id' => zrc.hostgroups.get_id('test_hostgroup')
269
+ }
270
+ zrc.usergroups.create(options)
271
+ ```
272
+
273
+ #### Deleting a user group
274
+ ```ruby
275
+ usergroup_id = zrc.usergroups.get_id({'name' => 'test_usergroup'})
276
+ zrc.usergroups.delete(usergroup_id)
277
+ ```
278
+
279
+ ### User Operations
280
+ #### Checking if a user exists
281
+ ```ruby
282
+ zrc.users.exists?({'alias' => 'max'})
283
+ ```
284
+
285
+ #### Getting the id of a user
286
+ ```ruby
287
+ zrc.users.get_id({'alias' => 'max'})
288
+ ```
289
+
290
+ #### Creating a user
291
+ ```ruby
292
+ group_id = zrc.usergroups.get_id({'name' => 'test_usergroup'})
293
+ user_options = Hash.new
294
+
295
+ user_options['alias'] = 'igor'
296
+ user_options['passwd'] = 'geheim'
297
+ user_options['usrgrps'] = [{
298
+ 'usrgrpid' => group_id
299
+ }]
300
+
301
+ user_options['user_medias'] = [{
302
+ 'mediatypeid' => 1,
303
+ 'sendto' => 'support@company.com',
304
+ 'active' => 0,
305
+ 'severity' => 63,
306
+ 'period' => '1-7,00:00-24:00'
307
+ }]
308
+
309
+ zrc.users.create(user_options)
310
+ ```
311
+
312
+ ### Actions Operations
313
+
314
+ #### Checking if an action exists
315
+ ```ruby
316
+ zrc.actions.exists?({'name' => 'Report problems to Zabbix administrators'})
317
+ ```
318
+
319
+ #### Getting the id of an action
320
+ ```ruby
321
+ zrc.actions.get_id({'name' => 'Report problems to Zabbix administrators'})
322
+ ```
323
+
324
+ #### Creating an action
325
+ ```ruby
326
+ usergroup_options = Hash.new({'name' = 'test_usergroup'})
327
+ action_options = Hash.new
328
+ action_options['name'] = 'Report problems to Zabbix administrators'
329
+ action_options['eventsource'] = 0
330
+ action_options['evaltype'] = 1 # AND
331
+ action_options['status'] = 1 # Disabled
332
+ action_options['esc_period'] = 3600
333
+ action_options['def_shortdata'] = '{TRIGGER.NAME}: {TRIGGER.STATUS}'
334
+ action_options['def_longdata'] = "{TRIGGER.NAME}: {TRIGGER.STATUS}\r\nLast value: {ITEM.LASTVALUE}\r\n\r\n{TRIGGER.URL}"
335
+ action_options['conditions'] = [{
336
+ 'conditiontype' => 0, # Hostgroup
337
+ 'operator' => 0, # =
338
+ 'value' => zrc.hostgroups.get_id('Templates')
339
+ },
340
+ # not in maintenance
341
+ {
342
+ 'conditiontype' => 16, # Maintenance
343
+ 'operator' => 7, # not in
344
+ 'value' => 'maintenance'
345
+ }]
346
+
347
+ action_options['operations'] = [{
348
+ 'operationtype' => 0,
349
+ 'esc_period' => 0,
350
+ 'esc_step_from' => 1,
351
+ 'esc_step_to' => 1,
352
+ 'evaltype' => 0,
353
+ 'opmessage_grp' => [{
354
+ 'usrgrpid' => zrc.usergroups.get_id(usergroup_options)
355
+ }],
356
+ 'opmessage' => {
357
+ 'default_msg' => 1,
358
+ 'mediatypeid' => 1
359
+ }
360
+ }]
361
+ zrc.actions.create(action_options)
362
+ ```
363
+
364
+ ### Remote client and tests
365
+ In order to run the rspec tests you need a running zabbix test server.
366
+
367
+ These environment variables also need to be set:
368
+
369
+ ZABBIX_API_URL
370
+ ZABBIX_API_LOGIN
371
+ ZABBIX_API_PASSWORD
372
+
373
+ ### TODOs
374
+ Open source the docker-compose setup of the whole zabbix installation.
375
+
376
+ ## Contributing
377
+
378
+ 1. Fork it
379
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
380
+ 3. Don't forget to write tests
381
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
382
+ 5. Push to the branch (`git push origin my-new-feature`)
383
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ require_relative 'base'
2
+
3
+ class Actions < Base
4
+ def exists?(options)
5
+ result = client.action_get({'filter' => {'name' => options['name']}})
6
+ if (result == nil || result.empty?)
7
+ return false
8
+ else
9
+ return true
10
+ end
11
+ end
12
+
13
+ def create(options)
14
+ client.action_create(options) unless exists?(options)
15
+ end
16
+
17
+ def get_id(options)
18
+ result = client.action_get({
19
+ 'filter' => {'name' => options['name']}})
20
+ result.first['actionid']
21
+ end
22
+
23
+ def delete(*action_ids)
24
+ client.action_delete(action_ids)
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'base'
2
+
3
+ class Applications < Base
4
+
5
+ def create(options)
6
+ client.application_create(options) unless exists?(options)
7
+ end
8
+
9
+ def exists?(options)
10
+ result = client.application_get({'filter' => {'name' => options['name']}})
11
+ if (result == nil || result.empty?)
12
+ false
13
+ else
14
+ true
15
+ end
16
+ end
17
+
18
+ def get_id(options)
19
+ if exists?(options)
20
+ client.application_get({
21
+ 'filter' => {'name' => options['name'],
22
+ 'hostid' => options['hostid']}}).first['applicationids']
23
+ else
24
+ raise NonExistingApplication, "Application #{options['name']} does not exist !"
25
+ end
26
+ end
27
+
28
+ class NonExistingApplication < StandardError; end
29
+
30
+ end
@@ -0,0 +1,7 @@
1
+ class Base
2
+ attr_reader :client
3
+
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+ end
@@ -0,0 +1,98 @@
1
+ require_relative 'base'
2
+
3
+ class HostGroups < Base
4
+
5
+ def mass_create(*names)
6
+ names.each do |group_name|
7
+ create(group_name)
8
+ end
9
+ end
10
+
11
+ def create(name)
12
+ client.hostgroup_create({'name' => name}) unless exists?(name)
13
+ end
14
+
15
+ def create_or_update(name)
16
+ if(exists?(name))
17
+ id = get_id(name)
18
+ client.hostgroup_update({'groupid' => id,'name' => name})
19
+ else
20
+ create(name)
21
+ end
22
+ end
23
+
24
+ def exists?(name)
25
+ result = client.hostgroup_get({'filter' => {'name' => [name]}})
26
+ if (result == nil || result.empty?)
27
+ return false
28
+ else
29
+ return true
30
+ end
31
+ end
32
+
33
+ def get_id(name)
34
+ if(exists?(name))
35
+ result = client.hostgroup_get({'filter' => {'name' => [name]}})
36
+ result[0]['groupid']
37
+ else
38
+ raise NonExistingHostgroup, "Hostgroup #{name} does not exist !"
39
+ end
40
+ end
41
+
42
+ def mass_delete(*names)
43
+ names.each do |group_name|
44
+ delete(group_name)
45
+ end
46
+ end
47
+
48
+ def get_host_ids_of(hostgroup)
49
+ result = client.hostgroup_get('filter' => {'name' => [hostgroup]}, 'selectHosts' => 'refer')
50
+ extract_host_ids(result)
51
+ end
52
+
53
+ def any_hosts?(hostgroup)
54
+ raise NonExistingHostgroup, "Hostgroup #{hostgroup} does not exist !" unless exists?(hostgroup)
55
+ result = client.hostgroup_get('filter' => {'name' => [hostgroup]}, 'selectHosts' => 'count').first['hosts'].to_i
56
+ #result = client.hostgroup_get('countOutput' => 'true', 'filter' => {'name' => [hostgroup]}, 'selectHosts' => 'count').to_i
57
+ result >= 1 ? true : false
58
+ end
59
+
60
+ def delete(name)
61
+ if(exists?(name))
62
+ # host cannot exist without a hostgroup, so we need to delete
63
+ # the attached hosts also
64
+ if(any_hosts?(name))
65
+ # delete all hosts attached to a hostgroup
66
+ host_ids = get_host_ids_of(name)
67
+ host_ids.each do |id|
68
+ client.host_delete([id])
69
+ end
70
+ # now it is ok to delete the group
71
+ client.hostgroup_delete([get_id(name)])
72
+ else
73
+ client.hostgroup_delete([get_id(name)])
74
+ end
75
+ else
76
+ raise NonExistingHostgroup, "Hostgroup #{name} does not exist !"
77
+ end
78
+ end
79
+
80
+ def get_all
81
+ # the fucking API also returns the ids and that's
82
+ # why we need to extract the names
83
+ host_groups_with_ids = client.hostgroup_get({'output' => ['name']})
84
+ extract_host_groups(host_groups_with_ids)
85
+ end
86
+
87
+ def extract_host_ids(query_result)
88
+ query_result.first['hosts'].map { |host| host['hostid'] }
89
+ end
90
+
91
+ def extract_host_groups(group_names_and_ids)
92
+ group_names_and_ids.map do |hostgroup|
93
+ hostgroup['name']
94
+ end
95
+ end
96
+
97
+ class NonExistingHostgroup < StandardError; end
98
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'base'
2
+
3
+ class Hostinterfaces < Base
4
+
5
+ def create(options)
6
+ client.hostinterface_create(options) unless exists?(options)
7
+ end
8
+
9
+ def exists?(options)
10
+ get(options).empty? ? false : true
11
+ end
12
+
13
+ def get(options)
14
+ client.hostinterface_get(
15
+ {'filter' => {'hostid' => options['hostid'],
16
+ 'port' => options['port'],
17
+ 'type' => options['type']},
18
+ 'output' => 'extend'})
19
+ end
20
+
21
+ end