one2influx 0.0.1
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/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:
|