rrd_rest_api 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rrd_repo.rb +97 -0
  3. data/server.rb +36 -3
  4. metadata +3 -3
  5. data/lib/rrd_query.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 929c34e0161b4b7e2f80444e6eeb8ef0c5827f43
4
- data.tar.gz: adef1a36e9481ee427fcad1371203dad67472cae
3
+ metadata.gz: 0bcb45d62b3521655a92b06314bc6a9ea551f1f9
4
+ data.tar.gz: bdc45d4f92e258f117386fd8e89e730dc40b1c3b
5
5
  SHA512:
6
- metadata.gz: 193a00a29b93069a30ca07f930d9273658fe75c650c591b50195a93e26b8e748740f2a72985526bdb290241c1c4de51d5709fad19a2ffd5e48c2fc057f2fea5d
7
- data.tar.gz: aa2009b5611a2edefbe074db085878ef8fc07ed9e422cea1e6a536b185b9e48dcd936d6f544fba55a89f55d94aaf4f00dccc3a8bdbf03b4d2add3476aa0246cb
6
+ metadata.gz: 026c76a12ed4114c96b73c64a674a3d038db949746f0522e8a24111afc712d55fa76fa30c97614f4ccf116a33043478f87231b96a57ae5d4bb23a1e0a5860b6a
7
+ data.tar.gz: e557e453ee8466052c333b60f7c33d3ffefea5e50586ccf86e550b5a8d5059897f629392ad3df8b54743397916234ffef69c52d0de57f0379e33b454b64864a5
data/lib/rrd_repo.rb ADDED
@@ -0,0 +1,97 @@
1
+ require 'rrd'
2
+
3
+ class RRDRepo
4
+ attr_reader :filename
5
+
6
+ def self.create(filename, datasources, start = Time.now)
7
+ one_day = 60 * 60 * 24
8
+
9
+ rrd = RRD::Base.new(filename)
10
+ rrd.create(:start => start, :step => 60) do
11
+ datasources.each do |name|
12
+ datasource name, :type => :gauge, :heartbeat => 120, :min => 0, :max => :unlimited
13
+ end
14
+ archive :average, :every => 60, :during => one_day
15
+ archive :average, :every => 300, :during => one_day
16
+ end
17
+ RRDRepo.new(filename)
18
+ end
19
+
20
+ def initialize(filename)
21
+ @filename = filename
22
+ end
23
+
24
+ def latest_value(datasource)
25
+ _rrd.info["ds[#{datasource}].last_ds"].to_f
26
+ end
27
+
28
+ def info
29
+ info = _rrd.info
30
+ archives = unflatten_archives(info)
31
+ {
32
+ :step => info["step"],
33
+ :archives => archives.map do |archive|
34
+ {
35
+ :consolidation_function => archive["cf"],
36
+ :resolution_sec => info["step"] * archive["pdp_per_row"],
37
+ :duration_sec => info["step"] * archive["pdp_per_row"] * archive["rows"]
38
+ }
39
+ end
40
+ }
41
+ end
42
+
43
+ def read(resolution, start_ts, end_ts, function = :average)
44
+ start_time = (start_ts.to_i / resolution) * resolution
45
+ end_time = (end_ts.to_i / resolution) * resolution
46
+ data = _rrd.fetch(
47
+ function,
48
+ :resolution => resolution,
49
+ :start => start_time,
50
+ :end => end_time
51
+ )
52
+ header, values = data.first, data[1..-1]
53
+ nan_filtered = values.reject { |v| v[1..-1].any?(&:nan?) }
54
+ nan_filtered.map { |v| Hash[header.zip(v)] }
55
+ end
56
+
57
+ def write(time, values = [])
58
+ _rrd.update(time, *values)
59
+ end
60
+
61
+ def _rrd
62
+ raise("Unable to open RRD, because it doesn't exist: #{@filename}") unless File.exist?(@filename)
63
+ @rrd ||= RRD::Base.new(@filename)
64
+ end
65
+
66
+ private
67
+
68
+ # Takes a flat hash output from an rrd "info" call and unflattens
69
+ # it by each archive.
70
+ #
71
+ # Input:
72
+ # {
73
+ # "rra[0].pdp_per_row"=>1,
74
+ # "rra[0].xff"=>0.5,
75
+ # "rra[1].pdp_per_row"=>168,
76
+ # "rra[1].xff"=>0.5,
77
+ # ...
78
+ # }
79
+ #
80
+ # Output:
81
+ # [
82
+ # {
83
+ # "pdp_per_row"=>1,
84
+ # "xff" => 0.5,
85
+ # },
86
+ # {
87
+ # "pdp_per_row" => 168,
88
+ # "xff" => 0.5
89
+ # }
90
+ # ]
91
+ def unflatten_archives(info)
92
+ info.select { |key, value| key.index("rra") == 0 }
93
+ .group_by { |elem| elem[0].split('.')[0] }
94
+ .sort_by { |rra, _| rra }
95
+ .map { |rra, values| Hash[values.map { |key, val| [key.split('.')[1], val] }] }
96
+ end
97
+ end
data/server.rb CHANGED
@@ -1,6 +1,7 @@
1
+ require 'json'
1
2
  require 'sinatra'
2
3
  require 'yaml'
3
- require File.expand_path(File.dirname(__FILE__) + "/lib/rrd_query")
4
+ require File.expand_path(File.dirname(__FILE__) + "/lib/rrd_repo")
4
5
 
5
6
  configure :production do
6
7
  set :port, 5678
@@ -16,8 +17,40 @@ get '/data/:file/latest/sum' do |file|
16
17
  end
17
18
 
18
19
  filename = _allowed_rrds[file]
19
- rrd_query = RRDQuery.new(filename)
20
- rrd_query.latest_value("sum").to_s
20
+ rrd_repo = RRDRepo.new(filename)
21
+ rrd_repo.latest_value("sum").to_s
22
+ end
23
+
24
+ get '/data/:file/read/' do |file|
25
+ unless _allowed_rrds.has_key?(file)
26
+ return 404
27
+ end
28
+
29
+ if params[:resolution].nil?
30
+ status 400
31
+ body "You must provide a 'resolution' query param in seconds"
32
+ return
33
+ end
34
+
35
+ if params[:duration].nil?
36
+ status 400
37
+ body "You must provide a 'duration' query param in seconds"
38
+ return
39
+ end
40
+
41
+ filename = _allowed_rrds[file]
42
+ rrd_repo = RRDRepo.new(filename)
43
+ info = rrd_repo.info
44
+ response.headers["X-RRD"] = "step=#{info[:step]}"
45
+ info[:archives].each_with_index do |archive, i|
46
+ response.headers["X-RRD-Archive#{i}"] = "cf=#{archive[:consolidation_function]}; resolution=#{archive[:resolution_sec]}; duration=#{archive[:duration_sec]}"
47
+ end
48
+
49
+ res = params[:resolution].to_i
50
+ dur = params[:duration].to_i
51
+ stop = Time.now
52
+ start = stop - dur
53
+ JSON.dump(rrd_repo.read(res, start, stop))
21
54
  end
22
55
 
23
56
  def _allowed_rrds
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rrd_rest_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - TempoIQ Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-19 00:00:00.000000000 Z
11
+ date: 2015-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sinatra
@@ -47,7 +47,7 @@ extensions: []
47
47
  extra_rdoc_files: []
48
48
  files:
49
49
  - config.ru
50
- - lib/rrd_query.rb
50
+ - lib/rrd_repo.rb
51
51
  - public/.gitemptydir
52
52
  - server.rb
53
53
  - tmp/.gitemptydir
data/lib/rrd_query.rb DELETED
@@ -1,18 +0,0 @@
1
- require 'rrd'
2
-
3
- class RRDQuery
4
- attr_reader :filename
5
-
6
- def initialize(filename)
7
- @filename = filename
8
- end
9
-
10
- def latest_value(datasource)
11
- _rrd.info["ds[#{datasource}].last_ds"].to_f
12
- end
13
-
14
- def _rrd
15
- raise("Unable to open RRD, because it doesn't exist: #{@filename}") unless File.exist?(@filename)
16
- @rrd ||= RRD::Base.new(@filename)
17
- end
18
- end