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 +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +55 -0
- data/LICENSE +22 -0
- data/README.md +383 -0
- data/Rakefile +1 -0
- data/lib/zapix/proxies/actions.rb +26 -0
- data/lib/zapix/proxies/applications.rb +30 -0
- data/lib/zapix/proxies/base.rb +7 -0
- data/lib/zapix/proxies/hostgroups.rb +98 -0
- data/lib/zapix/proxies/hostinterfaces.rb +21 -0
- data/lib/zapix/proxies/hosts.rb +77 -0
- data/lib/zapix/proxies/scenarios.rb +34 -0
- data/lib/zapix/proxies/templates.rb +30 -0
- data/lib/zapix/proxies/triggers.rb +40 -0
- data/lib/zapix/proxies/usergroups.rb +35 -0
- data/lib/zapix/proxies/users.rb +28 -0
- data/lib/zapix/version.rb +3 -0
- data/lib/zapix/zabbix_classes/host.rb +47 -0
- data/lib/zapix/zabbix_classes/interface.rb +42 -0
- data/lib/zapix/zabbix_rpc_client.rb +58 -0
- data/lib/zapix.rb +57 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/zapix_specs.rb +520 -0
- data/zapix.gemspec +27 -0
- metadata +141 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
class Hosts < Base
|
3
|
+
|
4
|
+
def get_id(name)
|
5
|
+
if(exists?(name))
|
6
|
+
client.host_get({'filter' => {'host' => name}}).first['hostid']
|
7
|
+
else
|
8
|
+
raise NonExistingHost, "Host #{name} does not exist !"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(options={})
|
13
|
+
client.host_create(options) unless exists?(options["host"])
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_or_update(options={})
|
17
|
+
raise EmptyHostname, 'Host name cannot be empty !' if options['host'].nil?
|
18
|
+
if exists?(options['host'])
|
19
|
+
id = get_id(options['host'])
|
20
|
+
options.merge!('hostid' => id)
|
21
|
+
client.host_update(options)
|
22
|
+
else
|
23
|
+
create(options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def unlink_and_clear_templates(options={})
|
28
|
+
template_ids = options['template_ids'].map { |id| {'templateid' => id}}
|
29
|
+
client.host_update({'hostid' => options['host_id'], 'templates_clear' => template_ids})
|
30
|
+
end
|
31
|
+
|
32
|
+
def update_templates(options={})
|
33
|
+
template_ids = options['template_ids'].map { |id| {'templateid' => id}}
|
34
|
+
client.host_update({'hostid' => options['host_id'], 'templates' => template_ids})
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_macros(options={})
|
38
|
+
client.host_update('hostid' => options['host_id'], 'macros' => options['macros'])
|
39
|
+
end
|
40
|
+
|
41
|
+
def exists?(name)
|
42
|
+
result = client.host_get({'filter' => {'host' => name}})
|
43
|
+
if (result == nil || result.empty?)
|
44
|
+
false
|
45
|
+
else
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_all
|
51
|
+
host_names_and_ids = client.host_get({'output' => ['name']})
|
52
|
+
|
53
|
+
# the fucking api ALWAYS returns the ids and that's
|
54
|
+
# why we need to extract the names separately
|
55
|
+
|
56
|
+
extract_host_names(host_names_and_ids)
|
57
|
+
end
|
58
|
+
|
59
|
+
def delete(name)
|
60
|
+
if exists?(name)
|
61
|
+
client.host_delete([get_id(name)])
|
62
|
+
else
|
63
|
+
raise NonExistingHost, "Host #{name} cannot be deleted because it does not exist !"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class NonExistingHost < StandardError; end
|
68
|
+
class EmptyHostname < StandardError; end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def extract_host_names(hosts_and_ids)
|
73
|
+
hosts_and_ids.map do |current_host|
|
74
|
+
current_host['name']
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
class Scenarios < Base
|
4
|
+
def create(options)
|
5
|
+
client.httptest_create(options) unless exists?(options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_id(options)
|
9
|
+
client.httptest_get({
|
10
|
+
'filter' => {'name' => options['name'], 'hostid' => options['hostid']}}).first['httptestid']
|
11
|
+
end
|
12
|
+
|
13
|
+
def delete(options)
|
14
|
+
client.httptest_delete(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def exists?(options)
|
18
|
+
result = client.httptest_get({
|
19
|
+
'countOutput' => true,
|
20
|
+
'filter' => {'name' => options['name'],
|
21
|
+
'hostid' => options['hostid']}})
|
22
|
+
|
23
|
+
result.to_i >= 1 ? true : false
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_all
|
27
|
+
scenarios = client.httptest_get({'output' => 'extend'})
|
28
|
+
names = extract_names(scenarios)
|
29
|
+
end
|
30
|
+
|
31
|
+
def extract_names(scenarios)
|
32
|
+
scenarios.map {|scenario| scenario['name']}
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
class Templates < Base
|
3
|
+
|
4
|
+
def exists?(name)
|
5
|
+
result = client.template_get({'filter' => {'name' => name}})
|
6
|
+
if (result == nil || result.empty?)
|
7
|
+
false
|
8
|
+
else
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create(options)
|
14
|
+
client.template_create(options) unless exists?(options['host'])
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_id(name)
|
18
|
+
if(exists?(name))
|
19
|
+
client.template_get({'filter' => {'name' => name}}).first['templateid']
|
20
|
+
else
|
21
|
+
raise NonExistingTemplate, "Template #{name} does not exist !"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_templates_for_host(id)
|
26
|
+
client.template_get({'hostids' => [id]}).map { |result_set| result_set['templateid'] }
|
27
|
+
end
|
28
|
+
|
29
|
+
class NonExistingTemplate < StandardError; end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
class Triggers < Base
|
3
|
+
|
4
|
+
def create(options)
|
5
|
+
client.trigger_create(options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def delete(*trigger_ids)
|
9
|
+
client.trigger_delete(trigger_ids)
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_id(options)
|
13
|
+
result = client.trigger_get({'output' => 'extend',
|
14
|
+
'expandExpression' => true})
|
15
|
+
id = extract_id(result, options['expression'])
|
16
|
+
unless id.nil?
|
17
|
+
id
|
18
|
+
else
|
19
|
+
raise NonExistingTrigger, "Trigger with expression #{options['expression']} not found."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class NonExistingTrigger < StandardError; end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def extract_id(triggers, expression)
|
28
|
+
result = nil
|
29
|
+
triggers.each do |trigger|
|
30
|
+
if trigger['expression'] == expression
|
31
|
+
result = trigger['triggerid']
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
class Usergroups < Base
|
4
|
+
|
5
|
+
def create(options)
|
6
|
+
client.usergroup_create(options) unless exists?(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def exists?(options)
|
10
|
+
#client.usergroup_exists(options)
|
11
|
+
result = client.usergroup_get({'filter' => {'name' => options['name']}})
|
12
|
+
if result.empty? || result == nil
|
13
|
+
false
|
14
|
+
else
|
15
|
+
true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_id(options)
|
20
|
+
if(exists?(options))
|
21
|
+
result = client.usergroup_get({
|
22
|
+
'filter' => {'name' => options['name']}})
|
23
|
+
result.first['usrgrpid']
|
24
|
+
else
|
25
|
+
raise NonExistingUsergroup, "Usergroup #{options['name']} does not exist !"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete(*group_ids)
|
30
|
+
client.usergroup_delete(group_ids)
|
31
|
+
end
|
32
|
+
|
33
|
+
class NonExistingUsergroup < StandardError; end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
class Users < Base
|
4
|
+
def create(options)
|
5
|
+
client.user_create(options) unless exists?(options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def exists?(options)
|
9
|
+
result = client.user_get({'filter' => {'alias' => options['alias']}})
|
10
|
+
result.empty? ? false : true
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_id(options)
|
14
|
+
if(exists?(options))
|
15
|
+
client.user_get({'filter' => {'alias' => options['alias']}}).first['userid']
|
16
|
+
else
|
17
|
+
raise NonExistingUser, "User #{options['alias']} does not exist !"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete(user_ids)
|
22
|
+
client.user_delete(user_ids)
|
23
|
+
end
|
24
|
+
|
25
|
+
class NonExistingUser < StandardError; end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Host
|
2
|
+
|
3
|
+
attr_accessor :group_ids, :template_ids, :interfaces, :macros
|
4
|
+
|
5
|
+
def initialize()
|
6
|
+
@group_ids = Array.new
|
7
|
+
@template_ids = Array.new
|
8
|
+
@interfaces = Array.new
|
9
|
+
@macros = Array.new
|
10
|
+
@properties = Hash.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_name(name)
|
14
|
+
@properties.merge!('host' => name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_group_ids(*ids)
|
18
|
+
ids.each do |id|
|
19
|
+
group_ids << {'groupid' => id}
|
20
|
+
end
|
21
|
+
@properties.merge!('groups' => group_ids)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_interfaces(*ifaces)
|
25
|
+
interfaces.concat(ifaces)
|
26
|
+
@properties.merge!('interfaces' => interfaces)
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_template_ids(*ids)
|
30
|
+
ids.each do |id|
|
31
|
+
template_ids << {'templateid' => id}
|
32
|
+
end
|
33
|
+
@properties.merge!('templates' => template_ids)
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_macros(*host_macros)
|
37
|
+
macros.concat(host_macros)
|
38
|
+
@properties.merge!('macros' => host_macros)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_hash
|
42
|
+
@properties
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
class Interface
|
4
|
+
include ActiveModel::Validations
|
5
|
+
|
6
|
+
attr_reader :type, :main, :useip, :ip, :dns, :port
|
7
|
+
validates_presence_of :type, :main, :useip, :ip, :dns, :port
|
8
|
+
|
9
|
+
# for more info see
|
10
|
+
# https://www.zabbix.com/documentation/2.0/manual/appendix/api/hostinterface/definitions#host_interface
|
11
|
+
# we assume ip and dns shall always be set
|
12
|
+
|
13
|
+
validates_inclusion_of :type, :in => 1..4
|
14
|
+
validates_inclusion_of :main, :in => 0..1
|
15
|
+
validates_inclusion_of :useip, :in => 0..1
|
16
|
+
|
17
|
+
def initialize(attributes)
|
18
|
+
@type = attributes['type'] ||= 1
|
19
|
+
@main = attributes['main'] ||= 1
|
20
|
+
@useip = attributes['useip'] ||= 1
|
21
|
+
@ip = attributes['ip'] = attributes['ip']
|
22
|
+
@dns = attributes['dns'] = attributes['dns']
|
23
|
+
@port = attributes['port'] = attributes['port'] ||= 10050
|
24
|
+
@result = {
|
25
|
+
'type' => type,
|
26
|
+
'main' => main,
|
27
|
+
'useip' => useip,
|
28
|
+
'ip' => ip,
|
29
|
+
'dns' => dns,
|
30
|
+
'port' => port
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_attribute_for_validation(key)
|
35
|
+
send(key)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_hash
|
39
|
+
@result
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class ZabbixRPCClient
|
6
|
+
|
7
|
+
attr_reader :uri, :debug
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@uri = URI.parse(options[:service_url])
|
11
|
+
@username = options[:username]
|
12
|
+
@password = options[:password]
|
13
|
+
@debug = options[:debug]
|
14
|
+
@auth_token = authenticate
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(name, *args)
|
18
|
+
method_name = map_name(name)
|
19
|
+
|
20
|
+
post_body = {
|
21
|
+
'method' => method_name,
|
22
|
+
'params' => args.first,
|
23
|
+
'id' => id,
|
24
|
+
'jsonrpc' => '2.0',
|
25
|
+
'auth' => @auth_token
|
26
|
+
}.to_json
|
27
|
+
|
28
|
+
resp = JSON.parse( http_post_request(post_body) )
|
29
|
+
raise JSONRPCError, resp['error'] if resp['error']
|
30
|
+
puts "[DEBUG] Get answer: #{resp}" if debug
|
31
|
+
resp["result"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def http_post_request(post_body)
|
35
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
36
|
+
http.use_ssl = true
|
37
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
38
|
+
request.content_type = 'application/json'
|
39
|
+
request.body = post_body
|
40
|
+
puts "[DEBUG] Send request: #{request.body}" if debug
|
41
|
+
http.request(request).body
|
42
|
+
end
|
43
|
+
|
44
|
+
def authenticate
|
45
|
+
p user_login({'user' => @username, 'password' => @password})
|
46
|
+
user_login({'user' => @username, 'password' => @password})
|
47
|
+
end
|
48
|
+
|
49
|
+
def id
|
50
|
+
rand(100000)
|
51
|
+
end
|
52
|
+
|
53
|
+
def map_name(name)
|
54
|
+
name.to_s.sub('_', '.')
|
55
|
+
end
|
56
|
+
|
57
|
+
class JSONRPCError < RuntimeError; end
|
58
|
+
end
|
data/lib/zapix.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'zapix/version'
|
2
|
+
require_relative 'zapix/zabbix_rpc_client'
|
3
|
+
|
4
|
+
class ZabbixAPI
|
5
|
+
attr_reader :client
|
6
|
+
|
7
|
+
def self.connect(options = {})
|
8
|
+
new(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@client = ZabbixRPCClient.new(options)
|
13
|
+
Dir["#{File.dirname(__FILE__)}/zapix/zabbix_classes/*.rb"].each { |f| load(f) }
|
14
|
+
Dir["#{File.dirname(__FILE__)}/zapix/proxies/*.rb"].each { |f| load(f) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def hostgroups
|
18
|
+
@hostgroups ||= HostGroups.new(client)
|
19
|
+
end
|
20
|
+
|
21
|
+
def hosts
|
22
|
+
@hosts ||= Hosts.new(client)
|
23
|
+
end
|
24
|
+
|
25
|
+
def templates
|
26
|
+
@templates ||= Templates.new(client)
|
27
|
+
end
|
28
|
+
|
29
|
+
def applications
|
30
|
+
@applications ||= Applications.new(client)
|
31
|
+
end
|
32
|
+
|
33
|
+
def scenarios
|
34
|
+
@scenarios ||= Scenarios.new(client)
|
35
|
+
end
|
36
|
+
|
37
|
+
def triggers
|
38
|
+
@triggers ||= Triggers.new(client)
|
39
|
+
end
|
40
|
+
|
41
|
+
def hostinterfaces
|
42
|
+
@hostinterfaces ||= Hostinterfaces.new(client)
|
43
|
+
end
|
44
|
+
|
45
|
+
def actions
|
46
|
+
@actions ||= Actions.new(client)
|
47
|
+
end
|
48
|
+
|
49
|
+
def usergroups
|
50
|
+
@usergroups ||= Usergroups.new(client)
|
51
|
+
end
|
52
|
+
|
53
|
+
def users
|
54
|
+
@users ||= Users.new(client)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require 'zapix'
|
8
|
+
RSpec.configure do |config|
|
9
|
+
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.filter_run :focus
|
13
|
+
|
14
|
+
# Run specs in random order to surface order dependencies. If you find an
|
15
|
+
# order dependency and want to debug it, you can fix the order by providing
|
16
|
+
# the seed, which is printed after each run.
|
17
|
+
# --seed 1234
|
18
|
+
config.order = 'random'
|
19
|
+
end
|