one2influx 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/one2influx +89 -0
- data/bin/one2influx.log +92 -0
- data/lib/one2influx.rb +20 -0
- data/lib/one2influx/config.rb +264 -0
- data/lib/one2influx/data.rb +84 -0
- data/lib/one2influx/influx.rb +156 -0
- data/lib/one2influx/one_object/cluster.rb +53 -0
- data/lib/one2influx/one_object/datastore.rb +30 -0
- data/lib/one2influx/one_object/host.rb +47 -0
- data/lib/one2influx/one_object/one_object.rb +73 -0
- data/lib/one2influx/one_object/virtual_machine.rb +49 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2538b53b0ce8cac2ffbb31b297dfe015f3d49e42
|
4
|
+
data.tar.gz: f8bae0a57a94d99818f79f529d7ddd38b421dee5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 492ab445d56b866b7bd99df28c22afc5e4f8a1ee4288f794b0d8bd89dc9ddad7951c2fed6607a3c19c590b9bdab548ae589874e65d44269a3389049041c5aaf8
|
7
|
+
data.tar.gz: bc944a9a54efb341f871a071da6fc0ce965fdf5f521efbcf8a0c12d2702202277637611b1a41522cc64943bedf055315adbe35a14889aee26bbe66c03376345f
|
data/bin/one2influx
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue Exception
|
6
|
+
$stderr.puts 'Failed to load rubygems!'
|
7
|
+
end
|
8
|
+
|
9
|
+
# add local dirs to load path if necessary
|
10
|
+
lib = File.expand_path(File.join('..', '..', 'lib'), __FILE__)
|
11
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
12
|
+
|
13
|
+
require 'one2influx'
|
14
|
+
|
15
|
+
# Load configuration
|
16
|
+
begin
|
17
|
+
$CFG = ::One2Influx::Config.new
|
18
|
+
rescue Exception => e
|
19
|
+
if $LOG.nil?
|
20
|
+
$stderr.puts e.message
|
21
|
+
else
|
22
|
+
$LOG.error e.message
|
23
|
+
$stderr.puts 'Failure, exiting. Check the log file.'
|
24
|
+
end
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
# Register termination signals
|
29
|
+
Signal.trap('INT') do
|
30
|
+
exit 0
|
31
|
+
end
|
32
|
+
Signal.trap('TERM') do
|
33
|
+
exit 0
|
34
|
+
end
|
35
|
+
|
36
|
+
# Checks connection with ONE using provided credentials
|
37
|
+
unless $CFG.is_one_available?
|
38
|
+
$stderr.puts 'Failure, exiting. Check the log file.'
|
39
|
+
exit 2
|
40
|
+
end
|
41
|
+
|
42
|
+
# Load InfluxDB connection link
|
43
|
+
begin
|
44
|
+
influx = ::One2Influx::Influx.new
|
45
|
+
rescue Exception => e
|
46
|
+
$LOG.error e.message
|
47
|
+
$stderr.puts 'Failure, exiting. Check the log file.'
|
48
|
+
exit 3
|
49
|
+
end
|
50
|
+
|
51
|
+
# Check if InfluxDB database and policy exist
|
52
|
+
unless influx.db_exists?
|
53
|
+
$stderr.puts 'Failure, exiting. Check the log file.'
|
54
|
+
exit 4
|
55
|
+
end
|
56
|
+
|
57
|
+
loop do
|
58
|
+
# Timestamp is same for all points in batch
|
59
|
+
# Get data from ONE
|
60
|
+
retries = 4
|
61
|
+
begin
|
62
|
+
data = ::One2Influx::Data.new
|
63
|
+
$LOG.info 'Successfully fetched data from ONE.'
|
64
|
+
rescue Exception => e
|
65
|
+
if retries < 0
|
66
|
+
$LOG.error 'Unable to fetch ONE data for the 5th time. Error:' +
|
67
|
+
"#{e.message}. Stacktrace: #{e.backtrace}"
|
68
|
+
sleep($CFG.sec_interval)
|
69
|
+
next
|
70
|
+
else
|
71
|
+
$LOG.warn "Unable to fetch ONE data. Trying #{retries+1} more times. " +
|
72
|
+
"Error: #{e.message}"
|
73
|
+
retries -= 1
|
74
|
+
sleep(0.01)
|
75
|
+
retry
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
# Store data
|
81
|
+
begin
|
82
|
+
influx.store(data.points)
|
83
|
+
$LOG.info "Successfully stored #{data.points.length} data points."
|
84
|
+
rescue Exception => e
|
85
|
+
$LOG.error e.message
|
86
|
+
end
|
87
|
+
|
88
|
+
sleep($CFG.sec_interval)
|
89
|
+
end
|
data/bin/one2influx.log
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Logfile created on 2015-04-29 17:25:53 +0200 by logger.rb/47272
|
2
|
+
E, [2015-05-06T13:21:09.497567 #22731] ERROR -- : Unable to find out ONE version with message: Connection refused - connect(2) for "localhost" port 2633
|
3
|
+
I, [2015-05-06T13:22:04.402884 #22917] INFO -- : Connection with ONE verified.
|
4
|
+
I, [2015-05-06T13:22:04.421713 #22917] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
5
|
+
I, [2015-05-06T13:22:04.574628 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
6
|
+
I, [2015-05-06T13:22:04.574757 #22917] INFO -- : Successfully fetched data from ONE.
|
7
|
+
E, [2015-05-06T13:22:04.574870 #22917] ERROR -- : exit
|
8
|
+
I, [2015-05-06T13:22:34.766527 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
9
|
+
I, [2015-05-06T13:22:34.766696 #22917] INFO -- : Successfully fetched data from ONE.
|
10
|
+
E, [2015-05-06T13:22:34.766805 #22917] ERROR -- : exit
|
11
|
+
I, [2015-05-06T13:23:04.887303 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
12
|
+
I, [2015-05-06T13:23:04.887481 #22917] INFO -- : Successfully fetched data from ONE.
|
13
|
+
E, [2015-05-06T13:23:04.887583 #22917] ERROR -- : exit
|
14
|
+
I, [2015-05-06T13:23:35.004802 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
15
|
+
I, [2015-05-06T13:23:35.004945 #22917] INFO -- : Successfully fetched data from ONE.
|
16
|
+
E, [2015-05-06T13:23:35.005052 #22917] ERROR -- : exit
|
17
|
+
I, [2015-05-06T13:24:05.143408 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
18
|
+
I, [2015-05-06T13:24:05.143577 #22917] INFO -- : Successfully fetched data from ONE.
|
19
|
+
E, [2015-05-06T13:24:05.143682 #22917] ERROR -- : exit
|
20
|
+
I, [2015-05-06T13:24:35.314966 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
21
|
+
I, [2015-05-06T13:24:35.315100 #22917] INFO -- : Successfully fetched data from ONE.
|
22
|
+
E, [2015-05-06T13:24:35.315197 #22917] ERROR -- : exit
|
23
|
+
I, [2015-05-06T13:24:52.210693 #23035] INFO -- : Connection with ONE verified.
|
24
|
+
I, [2015-05-06T13:24:52.226595 #23035] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
25
|
+
I, [2015-05-06T13:24:52.340054 #23035] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
26
|
+
I, [2015-05-06T13:24:52.340200 #23035] INFO -- : Successfully fetched data from ONE.
|
27
|
+
E, [2015-05-06T13:24:52.340320 #23035] ERROR -- : exit
|
28
|
+
I, [2015-05-06T13:25:05.424588 #22917] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
29
|
+
I, [2015-05-06T13:25:05.424739 #22917] INFO -- : Successfully fetched data from ONE.
|
30
|
+
E, [2015-05-06T13:25:05.424834 #22917] ERROR -- : exit
|
31
|
+
I, [2015-05-06T13:25:22.460081 #23035] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
32
|
+
I, [2015-05-06T13:25:22.460184 #23035] INFO -- : Successfully fetched data from ONE.
|
33
|
+
E, [2015-05-06T13:25:22.460258 #23035] ERROR -- : exit
|
34
|
+
I, [2015-05-06T13:37:58.353992 #23321] INFO -- : Connection with ONE verified.
|
35
|
+
I, [2015-05-06T13:37:58.367204 #23321] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
36
|
+
I, [2015-05-06T13:37:58.524869 #23321] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
37
|
+
I, [2015-05-06T13:37:58.525008 #23321] INFO -- : Successfully fetched data from ONE.
|
38
|
+
E, [2015-05-06T13:37:58.525149 #23321] ERROR -- : exit
|
39
|
+
I, [2015-05-06T13:38:44.753960 #23354] INFO -- : Connection with ONE verified.
|
40
|
+
I, [2015-05-06T13:38:44.769092 #23354] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
41
|
+
I, [2015-05-06T13:38:44.924625 #23354] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
42
|
+
I, [2015-05-06T13:38:44.924757 #23354] INFO -- : Successfully fetched data from ONE.
|
43
|
+
E, [2015-05-06T13:38:44.924866 #23354] ERROR -- : exit
|
44
|
+
I, [2015-05-06T13:41:42.382117 #23434] INFO -- : Connection with ONE verified.
|
45
|
+
I, [2015-05-06T13:41:42.398424 #23434] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
46
|
+
I, [2015-05-06T13:41:42.948566 #23434] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
47
|
+
I, [2015-05-06T13:41:42.948689 #23434] INFO -- : Successfully fetched data from ONE.
|
48
|
+
E, [2015-05-06T13:41:42.948786 #23434] ERROR -- : exit
|
49
|
+
I, [2015-05-06T13:42:00.006974 #23454] INFO -- : Connection with ONE verified.
|
50
|
+
I, [2015-05-06T13:42:00.133223 #23454] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
51
|
+
I, [2015-05-06T13:42:00.239825 #23454] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
52
|
+
I, [2015-05-06T13:42:00.239937 #23454] INFO -- : Successfully fetched data from ONE.
|
53
|
+
E, [2015-05-06T13:42:00.240007 #23454] ERROR -- : exit
|
54
|
+
I, [2015-05-06T13:42:13.784101 #23470] INFO -- : Connection with ONE verified.
|
55
|
+
I, [2015-05-06T13:42:13.798026 #23470] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
56
|
+
W, [2015-05-06T13:42:13.845268 #23470] WARN -- : Unable to fetch ONE data. Trying 5 more times. Error: no implicit conversion of nil into String
|
57
|
+
W, [2015-05-06T13:42:13.915400 #23470] WARN -- : Unable to fetch ONE data. Trying 4 more times. Error: no implicit conversion of nil into String
|
58
|
+
W, [2015-05-06T13:42:13.984934 #23470] WARN -- : Unable to fetch ONE data. Trying 3 more times. Error: no implicit conversion of nil into String
|
59
|
+
W, [2015-05-06T13:42:14.035001 #23470] WARN -- : Unable to fetch ONE data. Trying 2 more times. Error: no implicit conversion of nil into String
|
60
|
+
W, [2015-05-06T13:42:14.085218 #23470] WARN -- : Unable to fetch ONE data. Trying 1 more times. Error: no implicit conversion of nil into String
|
61
|
+
E, [2015-05-06T13:42:14.130828 #23470] ERROR -- : Unable to fetch ONE data for the 5th time. Error:no implicit conversion of nil into String. Stacktrace: ["/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/virtual_machine.rb:39:in `+'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/virtual_machine.rb:39:in `get_MEMORY_PERC'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:72:in `block in init_custom_metrics'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:71:in `each'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:71:in `init_custom_metrics'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:20:in `initialize'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/virtual_machine.rb:18:in `initialize'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:30:in `new'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:30:in `block (2 levels) in initialize'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:25:in `each'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:25:in `block in initialize'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/xml_pool.rb:35:in `call'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/xml_pool.rb:35:in `block in each_element'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.6.2/lib/nokogiri/xml/node_set.rb:187:in `block in each'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.6.2/lib/nokogiri/xml/node_set.rb:186:in `upto'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.6.2/lib/nokogiri/xml/node_set.rb:186:in `each'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/xml_pool.rb:34:in `each_element'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/pool.rb:152:in `each'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:22:in `initialize'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:62:in `new'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:62:in `block in <top (required)>'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:57:in `loop'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:57:in `<top (required)>'", "-e:1:in `load'", "-e:1:in `<main>'"]
|
62
|
+
I, [2015-05-06T13:42:22.673995 #23494] INFO -- : Connection with ONE verified.
|
63
|
+
I, [2015-05-06T13:42:22.688081 #23494] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
64
|
+
W, [2015-05-06T13:42:22.735880 #23494] WARN -- : Unable to fetch ONE data. Trying 5 more times. Error: no implicit conversion of nil into String
|
65
|
+
W, [2015-05-06T13:42:22.794775 #23494] WARN -- : Unable to fetch ONE data. Trying 4 more times. Error: no implicit conversion of nil into String
|
66
|
+
W, [2015-05-06T13:42:22.837748 #23494] WARN -- : Unable to fetch ONE data. Trying 3 more times. Error: no implicit conversion of nil into String
|
67
|
+
W, [2015-05-06T13:42:22.894808 #23494] WARN -- : Unable to fetch ONE data. Trying 2 more times. Error: no implicit conversion of nil into String
|
68
|
+
W, [2015-05-06T13:42:22.954857 #23494] WARN -- : Unable to fetch ONE data. Trying 1 more times. Error: no implicit conversion of nil into String
|
69
|
+
E, [2015-05-06T13:42:22.994985 #23494] ERROR -- : Unable to fetch ONE data for the 5th time. Error:no implicit conversion of nil into String. Stacktrace: ["/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/virtual_machine.rb:39:in `+'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/virtual_machine.rb:39:in `get_MEMORY_PERC'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:72:in `block in init_custom_metrics'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:71:in `each'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:71:in `init_custom_metrics'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/one_object.rb:20:in `initialize'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/one_object/virtual_machine.rb:18:in `initialize'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:30:in `new'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:30:in `block (2 levels) in initialize'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:25:in `each'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:25:in `block in initialize'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/xml_pool.rb:35:in `call'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/xml_pool.rb:35:in `block in each_element'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.6.2/lib/nokogiri/xml/node_set.rb:187:in `block in each'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.6.2/lib/nokogiri/xml/node_set.rb:186:in `upto'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/nokogiri-1.6.6.2/lib/nokogiri/xml/node_set.rb:186:in `each'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/xml_pool.rb:34:in `each_element'", "/home/ldoku/RubymineProjects/one2influx/vendor/bundle/ruby/2.2.0/gems/opennebula-4.12.0/lib/opennebula/pool.rb:152:in `each'", "/home/ldoku/RubymineProjects/one2influx/lib/one2influx/data.rb:22:in `initialize'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:62:in `new'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:62:in `block in <top (required)>'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:57:in `loop'", "/home/ldoku/RubymineProjects/one2influx/bin/one2influx:57:in `<top (required)>'", "-e:1:in `load'", "-e:1:in `<main>'"]
|
70
|
+
I, [2015-05-06T13:42:58.004202 #23537] INFO -- : Connection with ONE verified.
|
71
|
+
I, [2015-05-06T13:42:58.017566 #23537] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
72
|
+
E, [2015-05-06T13:42:58.054988 #23537] ERROR -- : Unable to get metric 'MEMORY_PERC' in One2Influx::VirtualMachine.
|
73
|
+
E, [2015-05-06T13:42:58.074978 #23537] ERROR -- : Unable to get metric 'MEMORY_PERC' in One2Influx::VirtualMachine.
|
74
|
+
E, [2015-05-06T13:42:58.090473 #23537] ERROR -- : Unable to get metric 'MEMORY_PERC' in One2Influx::VirtualMachine.
|
75
|
+
I, [2015-05-06T13:42:58.130001 #23537] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
76
|
+
I, [2015-05-06T13:42:58.130099 #23537] INFO -- : Successfully fetched data from ONE.
|
77
|
+
E, [2015-05-06T13:42:58.130189 #23537] ERROR -- : exit
|
78
|
+
I, [2015-05-06T13:43:47.863069 #23562] INFO -- : Connection with ONE verified.
|
79
|
+
I, [2015-05-06T13:43:47.909290 #23562] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
80
|
+
E, [2015-05-06T13:43:47.955788 #23562] ERROR -- : Unable to get metric 'MEMORY_PERC' in One2Influx::VirtualMachine.
|
81
|
+
E, [2015-05-06T13:43:47.975642 #23562] ERROR -- : Unable to get metric 'MEMORY_PERC' in One2Influx::VirtualMachine.
|
82
|
+
E, [2015-05-06T13:43:48.007135 #23562] ERROR -- : Unable to get metric 'MEMORY_PERC' in One2Influx::VirtualMachine.
|
83
|
+
I, [2015-05-06T13:43:48.034434 #23562] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
84
|
+
I, [2015-05-06T13:43:48.034562 #23562] INFO -- : Successfully fetched data from ONE.
|
85
|
+
E, [2015-05-06T13:43:48.034658 #23562] ERROR -- : exit
|
86
|
+
I, [2015-05-06T13:44:10.064663 #23582] INFO -- : Connection with ONE verified.
|
87
|
+
I, [2015-05-06T13:44:10.599592 #23582] INFO -- : Connection to InfluxDB database 'test' with retention policy 'ten_hours' verified.
|
88
|
+
I, [2015-05-06T13:44:10.750799 #23582] INFO -- : Stored data for 3 VMs, 2 hosts, 4 datastores and 1 clusters.
|
89
|
+
I, [2015-05-06T13:44:10.750902 #23582] INFO -- : Successfully fetched data from ONE.
|
90
|
+
E, [2015-05-06T13:44:10.751059 #23582] ERROR -- : exit
|
91
|
+
E, [2015-05-10T13:21:23.324353 #26300] ERROR -- : Unable to find out ONE version with message: Connection refused - connect(2) for "localhost" port 2633
|
92
|
+
E, [2015-05-11T00:16:42.153808 #12763] ERROR -- : Unable to find out ONE version with message: Connection refused - connect(2) for "localhost" port 2633
|
data/lib/one2influx.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module One2Influx; end
|
2
|
+
|
3
|
+
# Runtime dependencies
|
4
|
+
require 'opennebula'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'json'
|
7
|
+
require 'net/http'
|
8
|
+
require 'uri'
|
9
|
+
require 'logger'
|
10
|
+
|
11
|
+
|
12
|
+
# one2influx files
|
13
|
+
require 'one2influx/config'
|
14
|
+
require 'one2influx/data'
|
15
|
+
require 'one2influx/influx'
|
16
|
+
require 'one2influx/one_object/one_object'
|
17
|
+
require 'one2influx/one_object/host'
|
18
|
+
require 'one2influx/one_object/datastore'
|
19
|
+
require 'one2influx/one_object/virtual_machine'
|
20
|
+
require 'one2influx/one_object/cluster'
|
@@ -0,0 +1,264 @@
|
|
1
|
+
# Class for holding all configuration data, it is accessed by its only instance
|
2
|
+
# in global variable $CFG
|
3
|
+
class One2Influx::Config
|
4
|
+
|
5
|
+
##############################################################################
|
6
|
+
## EDIT THIS PART IF NECESSARY ##
|
7
|
+
##############################################################################
|
8
|
+
|
9
|
+
# Allowed values are number of seconds, minutes, hours
|
10
|
+
# separated by space
|
11
|
+
@@fetch_interval = '30 seconds'
|
12
|
+
|
13
|
+
# OpenNebula connection configuration
|
14
|
+
#####################################
|
15
|
+
@@one = {
|
16
|
+
# Login credentials separated by semicolon
|
17
|
+
credentials: 'user:password',
|
18
|
+
|
19
|
+
# XML_RPC endpoint where OpenNebula is listening
|
20
|
+
endpoint: 'http://localhost:2633/RPC2'
|
21
|
+
}
|
22
|
+
|
23
|
+
# InfluxDB connection configuration
|
24
|
+
###################################
|
25
|
+
@@influx = {
|
26
|
+
# Whether to use basic authentication
|
27
|
+
authenticate: false,
|
28
|
+
|
29
|
+
# Login credentials separated by semicolon
|
30
|
+
credentials: 'user:password',
|
31
|
+
|
32
|
+
# InfluxDB HTTP API endpoint
|
33
|
+
endpoint: 'http://localhost:8086',
|
34
|
+
|
35
|
+
# Database name
|
36
|
+
database: 'test',
|
37
|
+
|
38
|
+
# Retention policy for records with the smallest granularity
|
39
|
+
# you have to create retention policy manually if you want to change
|
40
|
+
# this one
|
41
|
+
policy: 'ten_hours'
|
42
|
+
}
|
43
|
+
|
44
|
+
# Logging configuration
|
45
|
+
#######################
|
46
|
+
@@log = {
|
47
|
+
# Level to use. Logger::INFO, Logger::WARN, Logger::ERROR are supported
|
48
|
+
level: Logger::INFO,
|
49
|
+
|
50
|
+
# Path to log file
|
51
|
+
path: ''
|
52
|
+
}
|
53
|
+
|
54
|
+
# Configuration of metrics and tags to be stored to InfluxDB
|
55
|
+
# Comment or uncomment metrics, tags or whole object depending on what you
|
56
|
+
# want to store.
|
57
|
+
##########################################################################
|
58
|
+
@@storage = {
|
59
|
+
# Host
|
60
|
+
host: {
|
61
|
+
tags: {
|
62
|
+
HOST_NAME: 'NAME',
|
63
|
+
CLUSTER_ID: 'CLUSTER_ID',
|
64
|
+
CLUSTER_NAME: 'CLUSTER',
|
65
|
+
DSS_IDS: '' # [string] IDs of datastores that this host uses
|
66
|
+
# encoded in form ,,ID_1,,ID_2...,,
|
67
|
+
},
|
68
|
+
metrics: [
|
69
|
+
'MEM_USAGE', # [kB] memory requested by VMs
|
70
|
+
'MAX_MEM', # [kB] total memory available in host
|
71
|
+
'FREE_MEM', # [kB] free memory returned by probes
|
72
|
+
'USED_MEM', # [kB] memory used by all host processes over MAX_MEM
|
73
|
+
'CPU_USAGE', # [%] usage of CPU calculated by ONE as the summatory
|
74
|
+
# CPU requested by all VMs running in the host
|
75
|
+
'MAX_CPU', # [%] total CPU in the host (number of cores * 100)
|
76
|
+
'FREE_CPU', # [%] free CPU as returned by the probes
|
77
|
+
'USED_CPU' # [%] CPU used by all host processes over a total
|
78
|
+
# of # cores * 100
|
79
|
+
],
|
80
|
+
cust_metrics: []
|
81
|
+
},
|
82
|
+
# Virtual machine
|
83
|
+
vm: {
|
84
|
+
tags: {
|
85
|
+
CLUSTER_ID: 'CLUSTER_ID',
|
86
|
+
CLUSTER_NAME: 'CLUSTER_NAME',
|
87
|
+
HOST_ID: 'HOST_ID',
|
88
|
+
HOST_NAME: 'HOST_NAME',
|
89
|
+
VM_NAME: 'NAME',
|
90
|
+
UID: 'UID', # [int] user's ID
|
91
|
+
GID: 'GID', # [int] group's ID
|
92
|
+
UNAME: 'UNAME', # [string] user's name
|
93
|
+
GNAME: 'GNAME' # [string] group's name
|
94
|
+
},
|
95
|
+
metrics: [
|
96
|
+
'MEMORY', # [kB] memory consumption
|
97
|
+
'CPU', # [%] 1 VCPU consumed (two fully consumed cpu is 200)
|
98
|
+
#'NET_TX', # [B] sent to the networ
|
99
|
+
#'NET_RX' # [B] received from the network
|
100
|
+
],
|
101
|
+
cust_metrics: [
|
102
|
+
#'MEMORY_PERC' # Computes percentage usage of memory for VM
|
103
|
+
]
|
104
|
+
|
105
|
+
},
|
106
|
+
# Datastore
|
107
|
+
ds: {
|
108
|
+
tags: {
|
109
|
+
DS_NAME: 'NAME',
|
110
|
+
CLUSTER_ID: 'CLUSTER_ID',
|
111
|
+
CLUSTER_NAME: 'CLUSTER',
|
112
|
+
TM_MAD: 'TM_MAD', # [shared|ssh|qcow2|vmfs|ceph|lvm|fs_lvm|dev]
|
113
|
+
# transfer manager
|
114
|
+
DS_MAD: 'DS_MAD', # [fs|vmfs|lvm|ceph|dev] datastore type
|
115
|
+
UID: 'UID', # [int] user's ID
|
116
|
+
GID: 'GID', # [int] group's ID
|
117
|
+
UNAME: 'UNAME', # [string] user's name
|
118
|
+
GNAME: 'GNAME', # [string] group's name
|
119
|
+
HOSTS_IDS: '' # [string] IDs of hosts that are using this
|
120
|
+
# datastore encoded in form ,,ID_1,,ID_2...,,
|
121
|
+
},
|
122
|
+
metrics: [
|
123
|
+
'TOTAL_MB', # [MB] total space available in datastore
|
124
|
+
'FREE_MB', # [MB] free space
|
125
|
+
'USED_MB' # [MB] used space
|
126
|
+
],
|
127
|
+
cust_metrics: []
|
128
|
+
},
|
129
|
+
# Cluster
|
130
|
+
cluster: {
|
131
|
+
tags: {
|
132
|
+
CLUSTER_NAME: 'NAME'
|
133
|
+
},
|
134
|
+
metrics: [
|
135
|
+
'CLUSTER_MEM_USAGE', # [kB] memory requested by all VMs in cluster
|
136
|
+
'CLUSTER_MAX_MEM', # [kB] total memory available in all hosts
|
137
|
+
'CLUSTER_FREE_MEM', # [kB] free memory of all hosts returned
|
138
|
+
# by probes
|
139
|
+
'CLUSTER_USED_MEM', # [kB] memory used by all processes of all
|
140
|
+
# hosts over MAX_MEM
|
141
|
+
'CLUSTER_CPU_USAGE', # [%] usage of CPU calculated by ONE as the
|
142
|
+
# sum of CPU requested by all VMs running
|
143
|
+
# in the cluster
|
144
|
+
'CLUSTER_MAX_CPU', # [%] total CPU in the cluster
|
145
|
+
# (number of cores * 100)
|
146
|
+
'CLUSTER_FREE_CPU', # [%] free CPU as returned by the probes
|
147
|
+
'CLUSTER_USED_CPU' # [%] CPU used by all processes of all hosts
|
148
|
+
# over a total of # cores * 100
|
149
|
+
],
|
150
|
+
cust_metrics: []
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
##############################################################################
|
155
|
+
## DO NOT EDIT BELOW THIS LINE ##
|
156
|
+
##############################################################################
|
157
|
+
|
158
|
+
attr_reader :sec_interval
|
159
|
+
# @@fetch_interval in seconds
|
160
|
+
@sec_interval = 0
|
161
|
+
|
162
|
+
public
|
163
|
+
# Group of getter methods for configuration class variables
|
164
|
+
def one
|
165
|
+
@@one
|
166
|
+
end
|
167
|
+
|
168
|
+
def influx
|
169
|
+
@@influx
|
170
|
+
end
|
171
|
+
|
172
|
+
def storage
|
173
|
+
@@storage
|
174
|
+
end
|
175
|
+
|
176
|
+
# Initializes logging, converts fetch interval from human readable form,
|
177
|
+
# adds tag ID to all metrics and converts VM's tags from human readable form
|
178
|
+
def initialize
|
179
|
+
log_path = @@log[:path] + 'one2influx.log'
|
180
|
+
begin
|
181
|
+
$LOG = Logger.new(log_path, 'daily', 30)
|
182
|
+
rescue Exception => e
|
183
|
+
raise "Unable to create log file. #{e.message}"
|
184
|
+
end
|
185
|
+
$LOG.level = @@log[:level]
|
186
|
+
|
187
|
+
convert_to_sec
|
188
|
+
prepare_storage_ids
|
189
|
+
prepare_vm_config
|
190
|
+
end
|
191
|
+
|
192
|
+
# Checks it is possible to connect to ONE with provided credentials.
|
193
|
+
def is_one_available?
|
194
|
+
begin
|
195
|
+
client = OpenNebula::Client.new(@@one[:credentials], @@one[:endpoint])
|
196
|
+
rescue Exception => e
|
197
|
+
$LOG.error "Unable to connect to ONE with message: #{e.message}"
|
198
|
+
return false
|
199
|
+
end
|
200
|
+
|
201
|
+
version = client.get_version
|
202
|
+
# Try to get ONE version just to check if it's possible to connect to ONE
|
203
|
+
if version.is_a? OpenNebula::Error
|
204
|
+
$LOG.error 'Unable to find out ONE version with message: '+version.message
|
205
|
+
return false
|
206
|
+
end
|
207
|
+
$LOG.info 'Connection with ONE verified.'
|
208
|
+
|
209
|
+
return true
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
# Adds obligatory ID tag to all storage objects in form OBJ_ID, where OBJ is
|
215
|
+
# object name. Therefore OneObjects will always have at least one tag, ID.
|
216
|
+
def prepare_storage_ids
|
217
|
+
@@storage.each do |object, values|
|
218
|
+
id_name = "#{object.to_s.upcase}_ID"
|
219
|
+
values[:tags][id_name.to_sym] = 'ID'
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# XML with virtual machine monitoring doesn't contain tags CLUSTER_ID,
|
224
|
+
# CLUSTER_NAME, HOST_ID and HOST_NAME so it needs to be loaded from the host
|
225
|
+
# running that VM.
|
226
|
+
# Therefore these tags are handled differently and needs to be separated from
|
227
|
+
# the rest into @@storage[:vm][:inh_tags]
|
228
|
+
def prepare_vm_config
|
229
|
+
inh_tags = %i(CLUSTER_ID CLUSTER_NAME HOST_ID HOST_NAME)
|
230
|
+
@@storage[:vm][:inh_tags] = @@storage[:vm][:tags].clone
|
231
|
+
|
232
|
+
# Get inherited tags into special hash for VMs only
|
233
|
+
@@storage[:vm][:inh_tags].keep_if do |key, value|
|
234
|
+
inh_tags.include? key
|
235
|
+
end
|
236
|
+
# Remove them from original hash
|
237
|
+
@@storage[:vm][:inh_tags].each do |key, value|
|
238
|
+
@@storage[:vm][:tags].delete(key)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Converts local variable human_interval to seconds
|
243
|
+
# and stores in sec_interval
|
244
|
+
def convert_to_sec
|
245
|
+
duration = @@fetch_interval.split(' ')
|
246
|
+
|
247
|
+
if duration.length != 2
|
248
|
+
raise "Invalid @@fetch_interval(=#{@@fetch_interval}) in config.rb."
|
249
|
+
end
|
250
|
+
|
251
|
+
case duration[1]
|
252
|
+
when /seconds?/
|
253
|
+
multiply = 1
|
254
|
+
when /minutes?/
|
255
|
+
multiply = 60
|
256
|
+
when /hours?/
|
257
|
+
multiply = 3600
|
258
|
+
else
|
259
|
+
raise "Invalid @@fetch_interval(=#{@@fetch_interval}) in config.rb."
|
260
|
+
end
|
261
|
+
|
262
|
+
@sec_interval = duration[0].to_i * multiply
|
263
|
+
end
|
264
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Wrapper for function that loads all data from OpenNebula
|
2
|
+
class One2Influx::Data
|
3
|
+
|
4
|
+
attr_reader :points
|
5
|
+
|
6
|
+
# Loads all data from ONE according to $CFG and stores it in
|
7
|
+
# instance variable @points
|
8
|
+
def initialize
|
9
|
+
@points = []
|
10
|
+
counter = {hosts: 0, vms: 0, dss: 0, clusters: 0}
|
11
|
+
# Connect to ONE
|
12
|
+
@client = OpenNebula::Client.new($CFG.one[:credentials], $CFG.one[:endpoint])
|
13
|
+
|
14
|
+
# Load pool of all hosts
|
15
|
+
host_pool = OpenNebula::HostPool.new(@client)
|
16
|
+
rc = host_pool.info
|
17
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
18
|
+
|
19
|
+
# Get data from all hosts in the pool
|
20
|
+
hosts_xml = {} # XML of all hosts, passed to theirs cluster
|
21
|
+
oo_hosts = [] # array of all instances of OneObject::Host
|
22
|
+
host_pool.each do |one_host|
|
23
|
+
host = ::One2Influx::Host.new(one_host.to_xml, @client)
|
24
|
+
# Get data from all VMs belonging to current host
|
25
|
+
host.vms.each do |vm_id|
|
26
|
+
xml_rep = OpenNebula::VirtualMachine.build_xml(vm_id)
|
27
|
+
one_vm = OpenNebula::VirtualMachine.new(xml_rep, @client)
|
28
|
+
rc = one_vm.info
|
29
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
30
|
+
vm = ::One2Influx::VirtualMachine.new(one_vm.to_xml, @client, host)
|
31
|
+
@points += vm.serialize_as_points
|
32
|
+
counter[:vms] += 1
|
33
|
+
end
|
34
|
+
hosts_xml[host.tags[:HOST_ID]] = one_host.to_xml
|
35
|
+
oo_hosts << host
|
36
|
+
@points += host.serialize_as_points
|
37
|
+
counter[:hosts] += 1
|
38
|
+
end
|
39
|
+
|
40
|
+
# Load pool of all clusters
|
41
|
+
cluster_pool = OpenNebula::ClusterPool.new(@client)
|
42
|
+
rc = cluster_pool.info
|
43
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
44
|
+
#
|
45
|
+
# Get data from all clusters in the pool
|
46
|
+
cluster_pool.each do |one_cluster|
|
47
|
+
cluster = ::One2Influx::Cluster.new(one_cluster.to_xml, @client,hosts_xml)
|
48
|
+
@points += cluster.serialize_as_points
|
49
|
+
counter[:clusters] += 1
|
50
|
+
end
|
51
|
+
|
52
|
+
# Load pool of all datastores
|
53
|
+
ds_pool = OpenNebula::DatastorePool.new(@client)
|
54
|
+
rc = ds_pool.info
|
55
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
56
|
+
|
57
|
+
# Get hash of all hosts for every datastore if these tags are required
|
58
|
+
# It has form {DS_ID_1: [HOST_ID_1, HOST_ID_2, ...], ...}
|
59
|
+
ds_has_hosts = {}
|
60
|
+
if $CFG.storage[:ds][:tags].has_key? :HOSTS_IDS
|
61
|
+
oo_hosts.each do |host|
|
62
|
+
host.datastores.each do |ds|
|
63
|
+
ds_has_hosts[ds] ||= []
|
64
|
+
ds_has_hosts[ds] << host.tags[:HOST_ID]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get data from all datastores in the pool
|
70
|
+
ds_pool.each do |one_ds|
|
71
|
+
ds = ::One2Influx::Datastore.new(one_ds.to_xml, @client)
|
72
|
+
hosts = ds_has_hosts[ds.tags[:DS_ID]]
|
73
|
+
hosts ||= []
|
74
|
+
# This doesn't do anything if tag HOSTS_IDS is not enabled
|
75
|
+
ds.add_hosts_ids(hosts)
|
76
|
+
@points += ds.serialize_as_points
|
77
|
+
counter[:dss] += 1
|
78
|
+
end
|
79
|
+
|
80
|
+
$LOG.info "Fetched data for #{counter[:vms]} VMs, #{counter[:hosts]} hosts" +
|
81
|
+
", #{counter[:dss]} datastores and #{counter[:clusters]} " +
|
82
|
+
'clusters.'
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Used for storing data to InfluxDB through HTTP API
|
2
|
+
class One2Influx::Influx
|
3
|
+
|
4
|
+
# Initializes class Influx.
|
5
|
+
# @raise [Exception] in case of error while getting UUID
|
6
|
+
def initialize
|
7
|
+
@authenticate = $CFG.influx[:authenticate]
|
8
|
+
if @authenticate
|
9
|
+
creds = $CFG.influx[:credentials].split(':')
|
10
|
+
raise 'InfluxDB credentials have invalid form!' if creds.length != 2
|
11
|
+
@user = creds[0]
|
12
|
+
@pass = creds[1]
|
13
|
+
end
|
14
|
+
uri = URI.parse($CFG.influx[:endpoint])
|
15
|
+
@host = uri.host
|
16
|
+
@port = uri.port
|
17
|
+
@db = $CFG.influx[:database]
|
18
|
+
@retention_policy = $CFG.influx[:policy]
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# @param [hash] points returned by OneObject.serialize_as_points
|
23
|
+
# @raise [Exception] in case of unsuccessful storing
|
24
|
+
def store(points)
|
25
|
+
# Split points by 2500 for better performance
|
26
|
+
points.each_slice(2500).to_a.each do |slice|
|
27
|
+
# Default InfluxDB payload form
|
28
|
+
payload = {
|
29
|
+
:database => @db,
|
30
|
+
:retentionPolicy => @retention_policy,
|
31
|
+
:points => slice
|
32
|
+
}
|
33
|
+
# puts "Total number of points is #{points.length}"
|
34
|
+
|
35
|
+
# Create InfluxDB write request
|
36
|
+
req = Net::HTTP::Post.new(
|
37
|
+
'/write',
|
38
|
+
initheader = {
|
39
|
+
'Content-Type' => 'application/json'
|
40
|
+
}
|
41
|
+
)
|
42
|
+
|
43
|
+
req.body = payload.to_json
|
44
|
+
response = make_request(req)
|
45
|
+
|
46
|
+
if (not response.nil?) && (response.code != '200')
|
47
|
+
raise 'Failed to store data to InfluxDB. Received HTTP code ' +
|
48
|
+
"#{response.code}, body: #{response.body}"
|
49
|
+
end
|
50
|
+
$LOG.info "Successfully stored #{slice.length} data points."
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Checks whether InfluxDB connection is possible, database @db exists
|
55
|
+
# and @retention_policy exists.
|
56
|
+
# @return [boolean]
|
57
|
+
def db_exists?
|
58
|
+
uri = URI('/query')
|
59
|
+
query = {:q => "SHOW RETENTION POLICIES #{@db}"}
|
60
|
+
uri.query = URI.encode_www_form(query)
|
61
|
+
|
62
|
+
req = Net::HTTP::Get.new(uri.to_s)
|
63
|
+
|
64
|
+
response = make_request(req)
|
65
|
+
|
66
|
+
# Was request successful?
|
67
|
+
if response.nil?
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
# Check for invalid HTTP response codes
|
72
|
+
if response.code.to_i == 401
|
73
|
+
$LOG.error "Unauthorized user '#{@user}', unable to verify connection" +
|
74
|
+
' to InfluxDB.'
|
75
|
+
return false
|
76
|
+
elsif response.code.to_i != 200
|
77
|
+
$LOG.error 'Failed to store data to InfluxDB. Received HTTP code ' +
|
78
|
+
"#{response.code}, body: #{response.body}"
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
|
82
|
+
# Parse response
|
83
|
+
begin
|
84
|
+
response = JSON.parse(response.body)
|
85
|
+
rescue JSON::ParserError => e
|
86
|
+
$LOG.error 'Unable to parse InfluxDB response, while verifying ' +
|
87
|
+
"connection to database '#{@db}': #{e}. " +
|
88
|
+
"Received: #{response.body}"
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
|
92
|
+
begin
|
93
|
+
if response['results'][0].has_key? 'error'
|
94
|
+
$LOG.error "Unable to verify connection to InfluxDB database '#{@db}'" +
|
95
|
+
" with message: #{response['results'][0]['error']}"
|
96
|
+
return false
|
97
|
+
end
|
98
|
+
|
99
|
+
response['results'][0]['series'][0]['values'].each do |policy|
|
100
|
+
if policy[0] == @retention_policy
|
101
|
+
$LOG.info "Connection to InfluxDB database '#{@db}' with retention " +
|
102
|
+
"policy '#{@retention_policy}' verified."
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
rescue Exception
|
107
|
+
# Handle index out of bounds etc. exceptions
|
108
|
+
$LOG.error "Unable to verify connection to InfluxDB database '#{@db}'. " +
|
109
|
+
'Invalid InfluxDB response format.'
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
$LOG.error "InfluxDB database '#{@db}' does not contain supplied " +
|
113
|
+
"retention policy '#{@retention_policy}'."
|
114
|
+
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# @param [Net::HTTP::Post|Net::HTTP::Get] request
|
121
|
+
# @raise [Exception] Net::*
|
122
|
+
# @return [Net::HTTPResponse]
|
123
|
+
def make_request(request)
|
124
|
+
if @authenticate
|
125
|
+
request.basic_auth @user, @pass
|
126
|
+
end
|
127
|
+
|
128
|
+
retries = 4
|
129
|
+
begin
|
130
|
+
http = Net::HTTP.new(@host, @port)
|
131
|
+
http.read_timeout = 2
|
132
|
+
response = http.start do |http|
|
133
|
+
http.request(request)
|
134
|
+
end
|
135
|
+
rescue Exception => e
|
136
|
+
if retries < 0 then
|
137
|
+
if e.is_a? Net::ReadTimeout
|
138
|
+
raise 'Unable to post data to InfluxDB for 5th time! ' +
|
139
|
+
'Timed out, possibly not stored.'
|
140
|
+
else
|
141
|
+
raise 'Unable to post data to InfluxDB for 5th time! ' +
|
142
|
+
"Error: #{e.message}."
|
143
|
+
end
|
144
|
+
return nil
|
145
|
+
else
|
146
|
+
$LOG.warn "Unable to post data to InfluxDB! Trying #{retries+1} more " +
|
147
|
+
"times. Error: #{e.message}."
|
148
|
+
retries -= 1
|
149
|
+
sleep(0.01)
|
150
|
+
retry
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
return response
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Representation of ONE cluster
|
2
|
+
class One2Influx::Cluster < ::One2Influx::OneObject
|
3
|
+
|
4
|
+
#
|
5
|
+
# @param [string] xml representation of cluster
|
6
|
+
# @param [OpenNebula::Client] client connection link to ONE API
|
7
|
+
# @param [hash] hosts_xml xml representations of hosts in this cluster,
|
8
|
+
# in hash form {HOST_ID : XML_STRING}
|
9
|
+
def initialize(xml, client, hosts_xml)
|
10
|
+
# Load configuration
|
11
|
+
@tag_names = $CFG.storage[:cluster][:tags]
|
12
|
+
@metric_names = $CFG.storage[:cluster][:metrics]
|
13
|
+
@custom_metric_names = $CFG.storage[:cluster][:cust_metrics]
|
14
|
+
@hosts_xml = hosts_xml
|
15
|
+
|
16
|
+
super(xml, client)
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# Overrides OneObject init_metrics because cluster itself doesn't
|
22
|
+
# have any own metrics, so they are gathered as sum of metrics of
|
23
|
+
# hosts that belong to this cluster
|
24
|
+
def init_metrics
|
25
|
+
@metric_names.each do |metric|
|
26
|
+
@metrics[metric.to_s] = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
host_ids = @doc.xpath('//HOSTS/ID').map { |node| node.content }
|
30
|
+
host_ids.each do |id|
|
31
|
+
host_doc = Nokogiri::XML(@hosts_xml[id])
|
32
|
+
@metric_names.each do |metric|
|
33
|
+
host_metric = metric.split('CLUSTER_')[1]
|
34
|
+
unless host_metric.nil?
|
35
|
+
ni_element = host_doc.css(host_metric).first
|
36
|
+
if ni_element.nil?
|
37
|
+
$LOG.error "Unable to get metric '#{metric}' in #{self.class}."
|
38
|
+
else
|
39
|
+
@metrics[metric.to_s] += ni_element.content.to_i
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get real percentage for cluster
|
46
|
+
hosts_count = host_ids.length == 0 ? 1 : host_ids.length
|
47
|
+
@metrics.each do |metric, value|
|
48
|
+
if metric.to_s.include? 'CPU'
|
49
|
+
@metrics[metric] = value / hosts_count
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Representation of ONE datastore
|
2
|
+
class One2Influx::Datastore < ::One2Influx::OneObject
|
3
|
+
|
4
|
+
#
|
5
|
+
# @param [string] xml representation of datastore
|
6
|
+
# @param [OpenNebula::Client] client connection link to ONE API
|
7
|
+
def initialize(xml, client)
|
8
|
+
# Load configuration
|
9
|
+
@tag_names = $CFG.storage[:ds][:tags]
|
10
|
+
@metric_names = $CFG.storage[:ds][:metrics]
|
11
|
+
@custom_metric_names = $CFG.storage[:ds][:cust_metrics]
|
12
|
+
|
13
|
+
# Parsing HOST_ID_X as normal tag_name would cause error
|
14
|
+
if @tag_names.has_key? :HOSTS_IDS
|
15
|
+
@tag_names.delete :HOSTS_IDS
|
16
|
+
end
|
17
|
+
|
18
|
+
super(xml, client)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add tag HOSTS_IDS a string containing IDs of all hosts associated
|
22
|
+
# with this datastore in form for each host associated with this datastore in
|
23
|
+
# form ,,ID_1,,ID_2...,,
|
24
|
+
# @param [array] hosts array of hosts IDs that are using this datastore
|
25
|
+
def add_hosts_ids(hosts)
|
26
|
+
unless hosts.empty?
|
27
|
+
@tags[:HOSTS_IDS] = ',,' + hosts.join(',,') + ',,'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Representation of ONE host
|
2
|
+
class One2Influx::Host < ::One2Influx::OneObject
|
3
|
+
|
4
|
+
attr_reader :datastores
|
5
|
+
|
6
|
+
#
|
7
|
+
# @param [string] xml representation of host
|
8
|
+
# @param [OpenNebula::Client] client connection link to ONE API
|
9
|
+
def initialize(xml, client)
|
10
|
+
# Load configuration
|
11
|
+
@tag_names = $CFG.storage[:host][:tags]
|
12
|
+
@metric_names = $CFG.storage[:host][:metrics]
|
13
|
+
@custom_metric_names = $CFG.storage[:host][:cust_metrics]
|
14
|
+
|
15
|
+
|
16
|
+
@doc = Nokogiri::XML(xml)
|
17
|
+
@tags = Hash.new
|
18
|
+
load_datastores
|
19
|
+
if @tag_names.has_key? :DSS_IDS
|
20
|
+
@tag_names.delete :DSS_IDS
|
21
|
+
unless @datastores.empty?
|
22
|
+
@tags[:DSS_IDS] = ',,' + @datastores.join(',,') + ',,'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
super(xml, client)
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# @return [array] IDs of VMs
|
31
|
+
def vms
|
32
|
+
@doc.xpath('//VMS/ID').map do |node|
|
33
|
+
node.content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Initializes @datastores array of IDs for datastores associated with
|
40
|
+
# this host
|
41
|
+
def load_datastores
|
42
|
+
@datastores = []
|
43
|
+
@doc.xpath('//DATASTORES/DS/ID').each do |ds|
|
44
|
+
@datastores << ds.content
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# 'Abstract' class for OpenNebula's objects representation
|
2
|
+
class One2Influx::OneObject
|
3
|
+
|
4
|
+
attr_reader :tags, :metrics, :doc
|
5
|
+
|
6
|
+
# Creates mapping between ONE XML names and InfluxDB storage names.
|
7
|
+
# Loads all tags, metrics and custom metrics from given XML.
|
8
|
+
# @param [string] xml representation of OneObject
|
9
|
+
# @param [OpenNebula::Client] client connection link to ONE API
|
10
|
+
def initialize(xml, client)
|
11
|
+
@tags ||= Hash.new
|
12
|
+
@metrics ||= Hash.new
|
13
|
+
@doc ||= Nokogiri::XML(xml)
|
14
|
+
@client = client
|
15
|
+
|
16
|
+
init_tags
|
17
|
+
init_metrics
|
18
|
+
init_custom_metrics
|
19
|
+
end
|
20
|
+
|
21
|
+
# Serialize OneObject instance to InfluxDB point form
|
22
|
+
def serialize_as_points
|
23
|
+
points = []
|
24
|
+
@metrics.each do |metric_name, metric_value|
|
25
|
+
points << {
|
26
|
+
:name => metric_name,
|
27
|
+
:tags => @tags,
|
28
|
+
:fields => {
|
29
|
+
:value => metric_value.to_f
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
return points
|
35
|
+
end
|
36
|
+
|
37
|
+
# Called in case of misconfiguration and invalid custom metric method
|
38
|
+
# was called
|
39
|
+
def method_missing(name, *args, &block)
|
40
|
+
$LOG.error "Invalid method '#{name}' was called from #{self.class}! " #+
|
41
|
+
# "Stacktrace: #{e.backtrace}"
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def init_tags
|
47
|
+
@tag_names.each do |influx_name, one_name|
|
48
|
+
ni_element = @doc.css(one_name).first
|
49
|
+
if ni_element.nil?
|
50
|
+
$LOG.error "Unable to get tag '#{one_name}' in #{self.class}."
|
51
|
+
else
|
52
|
+
@tags[influx_name.to_sym] = ni_element.content
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def init_metrics
|
58
|
+
@metric_names.each do |metric|
|
59
|
+
ni_element = @doc.css(metric).first
|
60
|
+
if ni_element.nil?
|
61
|
+
$LOG.error "Unable to get metric '#{metric}' in #{self.class}."
|
62
|
+
else
|
63
|
+
@metrics[metric.to_sym] = ni_element.content
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def init_custom_metrics
|
69
|
+
@custom_metric_names.each do |metric|
|
70
|
+
@metrics[metric.to_sym] = self.send("get_#{metric.to_s}")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Representation of ONE virtual machine
|
2
|
+
class One2Influx::VirtualMachine < ::One2Influx::OneObject
|
3
|
+
|
4
|
+
#
|
5
|
+
# @param [string] xml representation of VM
|
6
|
+
# @param [OpenNebula::Client] client connection link to ONE API
|
7
|
+
# @param [One2Influx::Host] parent_host owner of this VM
|
8
|
+
def initialize(xml, client, parent_host)
|
9
|
+
# Load configuration
|
10
|
+
@tag_names = $CFG.storage[:vm][:tags]
|
11
|
+
@metric_names = $CFG.storage[:vm][:metrics]
|
12
|
+
@custom_metric_names = $CFG.storage[:vm][:cust_metrics]
|
13
|
+
|
14
|
+
# Assign tags inherited from parent host
|
15
|
+
@tags = Hash.new
|
16
|
+
$CFG.storage[:vm][:inh_tags].each do |name, value|
|
17
|
+
@tags[name] = parent_host.tags[value.to_sym]
|
18
|
+
end
|
19
|
+
super(xml, client)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Computes percentage usage of memory for virtual machine.
|
23
|
+
# Values might go over 1.0 as there is an overhead
|
24
|
+
# @return [float] current usage over max usage
|
25
|
+
def get_MEMORY_PERC
|
26
|
+
template_id = @doc.xpath('//TEMPLATE').first
|
27
|
+
if template_id.nil? || template_id.content.nil?
|
28
|
+
$LOG.error "Unable to get metric 'MEMORY_PERC' in #{self.class}."
|
29
|
+
return
|
30
|
+
end
|
31
|
+
template_id = template_id.content
|
32
|
+
template = OpenNebula::Template.new(OpenNebula::Template.build_xml(template_id), @client)
|
33
|
+
rc = template.info
|
34
|
+
raise rc.message if OpenNebula.is_error?(rc)
|
35
|
+
|
36
|
+
doc = Nokogiri::XML(template.to_xml)
|
37
|
+
ni_element = doc.xpath('//TEMPLATE/MEMORY').first
|
38
|
+
puts @metrics
|
39
|
+
if ni_element.nil? || @metrics[:MEMORY].nil?
|
40
|
+
$LOG.error "Unable to get metric 'MEMORY_PERC' in #{self.class}."
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
# Convert //TEMPLATE/MEMORY from MB to kB as //VM/CPU is in kB
|
45
|
+
max_mem = ni_element.content.to_f * 1000.0
|
46
|
+
|
47
|
+
@metrics[:MEMORY].to_f / max_mem
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: one2influx
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matej Zidek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: opennebula
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.12'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: gyoku
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubystats
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.2'
|
83
|
+
description: One2influx is small ruby daemon for getting monitoring data from OpenNebula's
|
84
|
+
XML-RPC API and storing it to InfluxDB. It needs Ruby 2+ to run.
|
85
|
+
email: zidek.matej@gmail.com
|
86
|
+
executables:
|
87
|
+
- one2influx
|
88
|
+
- one2influx.log
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- bin/one2influx
|
93
|
+
- bin/one2influx.log
|
94
|
+
- lib/one2influx.rb
|
95
|
+
- lib/one2influx/config.rb
|
96
|
+
- lib/one2influx/data.rb
|
97
|
+
- lib/one2influx/influx.rb
|
98
|
+
- lib/one2influx/one_object/cluster.rb
|
99
|
+
- lib/one2influx/one_object/datastore.rb
|
100
|
+
- lib/one2influx/one_object/host.rb
|
101
|
+
- lib/one2influx/one_object/one_object.rb
|
102
|
+
- lib/one2influx/one_object/virtual_machine.rb
|
103
|
+
homepage: http://rubygems.org/gems/hola
|
104
|
+
licenses:
|
105
|
+
- Apache License 2.0
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 2.0.0
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.4.5
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Daemon for getting monitoring data from OpenNebula's XML-RPC API and storing
|
127
|
+
them to InfluxDB.
|
128
|
+
test_files: []
|
129
|
+
has_rdoc:
|