ref: refs/heads/network
commit 51596eb659188f93210a1022476a30641b347c08
Author: Duncan Mac-Vicar P
Date: Thu Sep 10 18:43:15 2009 +0200
- use safe types
- rewriten parsing of rrdtool output (too complex)
- adapt testcases
- still missing , find by id, as id contains /
---
.../status/app/controllers/metrics_controller.rb | 27 ++++-
plugins/status/app/models/metric.rb | 122 +++++++++++---------
plugins/status/test/unit/metric_test.rb | 58 +++++-----
3 files changed, 116 insertions(+), 91 deletions(-)
diff --git a/plugins/status/app/controllers/metrics_controller.rb b/plugins/status/app/controllers/metrics_controller.rb
index d9d4221..e20c94d 100644
--- a/plugins/status/app/controllers/metrics_controller.rb
+++ b/plugins/status/app/controllers/metrics_controller.rb
@@ -65,23 +65,38 @@ class MetricsController < ApplicationController
# GET /status
# GET /status.xml
+ #
def index
- opts = {}
- opts.merge!(params)
- @metrics = Metric.find(:all, opts)
+
+ conditions = {}
+
+ # support filtering by host, plugin, plugin_instance ...
+ [:host, :plugin, :type, :plugin_instance, :type_instance, :plugin_full, :type_full ].each do |key|
+ if params.has_key?(key)
+ conditions[key] = params[key]
+ end
+ end
+
+ @metrics = Metric.find(:all, conditions)
+ respond_to do |format|
+ format.xml { render :xml => @metrics.to_xml(:root => 'metrics', :data => false) }
+ end
+
end
# GET /status/1
# GET /status/1.xml
def show
#permission_check("org.opensuse.yast.system.status.read")
- @metrics =
begin
- @status = Status.new
+ @metric = Metric.find(CGI.unescape(params[:id]))
stop = params[:stop].blank? ? Time.now : Time.at(params[:stop].to_i)
start = params[:start].blank? ? stop - 300 : Time.at(params[:start].to_i)
- @status.collect_data(start, stop, params[:data])
+
+ respond_to do |format|
+ format.xml { render :xml => @metric.to_xml(:start => start, :stop => stop) }
+ end
rescue Exception => e
render :text => e.to_s, :status => 400 # bad request
end
diff --git a/plugins/status/app/models/metric.rb b/plugins/status/app/models/metric.rb
index c19f8ee..41c92af 100644
--- a/plugins/status/app/models/metric.rb
+++ b/plugins/status/app/models/metric.rb
@@ -147,8 +147,11 @@ class Metric
when :all then opts.empty? ? find_all : find_multiple(opts)
# in this case, the options are the first
# parameter
- when Hash
- else find_multiple(what.merge(opts))
+ when Hash then find_multiple(what.merge(opts))
+ when String
+ raise "hello"
+ find_multiple({:identifier => what})
+ else nil
end
end
@@ -205,27 +208,28 @@ class Metric
data_opts = {}
data_opts[:start] = opts[:start] if opts.has_key?(:start)
data_opts[:stop] = opts[:stop] if opts.has_key?(:stop)
-
- metric_data = data(data_opts)
- starttime = metric_data['starttime']
- interval = metric_data['interval']
xml = opts[:builder] ||= Builder::XmlMarkup.new(opts)
xml.instruct! unless opts[:skip_instruct]
xml.metric do
- xml.id self.identifier
- xml.host self.host
- xml.plugin self.plugin
- xml.plugin_instance self.plugin_instance
- xml.type self.type
- xml.type_instance self.type_instance
+ xml.id identifier
+ xml.host host
+ xml.plugin plugin
+ xml.plugin_instance plugin_instance
+ xml.type type
+ xml.type_instance type_instance
+
+ # serialize data unless it is disabled
+ unless opts.has_key?(:data) and !opts[:data]
+ metric_data = data(data_opts)
+ starttime = metric_data['starttime']
+ interval = metric_data['interval']
- metric_data.each do |col, values|
- next if col == "starttime"
- next if col == "interval"
- xml.data(:column => col, :start => starttime, :interval => interval ) do
- values.each { |time, value| xml.value value }
+ metric_data.each do |col, values|
+ next if col == "starttime"
+ next if col == "interval"
+ xml.data(:column => col, :start => starttime.to_i, :interval => interval ) { values.each { |time, value| xml.value value } }
end
end
@@ -243,60 +247,68 @@ class Metric
stop = opts.has_key?(:stop) ? opts[:stop] : Time.now
start = opts.has_key?(:stop) ? opts[:stop] : stop - 300
- cmd = IO.popen("rrdtool fetch #{file} AVERAGE --start #{start.strftime("%H:%M,%m/%d/%Y")} --end #{stop.strftime("%H:%M,%m/%d/%Y")}")
+ cmd = IO.popen("rrdtool fetch #{file} AVERAGE --start #{start.strftime("%H:%M,%m/%d/%Y")} --end #{stop.strftime("%H:%M,%m/%d/%Y")}")
output = cmd.read
cmd.close
+
+ raise output if $?.exitstatus != 0
+
output
end
def self.read_metric_file(rrdfile, opts={})
result = Hash.new
+
output = run_rrdtool(rrdfile, opts)
raise "Error running collectd rrdtool" if output =~ /ERROR/ or output.nil?
-
- labels=""
+
output = output.gsub(",", ".") # translates eg. 1,234e+07 to 1.234e+07
- lines = output.split "\n"
- # set label names
- lines[0].each do |l|
- if l =~ /\D*/
- labels = l.split " "
+ line_count = 0
+ result["starttime"] = 9.9e+99
+
+ times = []
+ labels = []
+ output.each_line do |line|
+ line_count += 1
+ next if line.blank?
+
+ # read the labels for the first line
+ if line_count == 1
+ labels = line.split(" ")
+ # no labels, no data
+ return {} if labels.empty?
+ next
end
+
+ time_str, values_str = line.split(":")
+ time = Time.at(time_str.to_i)
+
+ # store time to get the starttime and interval
+ times << time
+
+ values = values_str.split(" ").map {|x| x == "nan" ? nil : x.to_f}
+
+ values.each_with_index do |value, index|
+ label = labels[index]
+ result[label] = {} if not result.has_key?(label)
+ result[label][time] = value
+ end
end
- unless labels.blank?
- # set values for each label and time
- # evaluates interval and starttime once for each metric (not each label)
- nexttime = 9.9e+99
- result["starttime"] = 9.9e+99
- lines.each do |l| # each time
- next if l.blank?
- if l =~ /\d*:\D*/
- pair = l.split ":"
- values = pair[1].split " "
- column = 0
- values.each do |v| # each label
- unless result["interval"] # already defined?
- # get the least distance to evaluate time interval
- if pair[0].to_i < result["starttime"].to_i
- result["starttime"] = pair[0].to_i
- elsif pair[0].to_i < nexttime and pair[0].to_i > result["starttime"].to_i
- nexttime = pair[0].to_i
- end
- end
- v = "invalid" if v == "nan" #store valid values only
- result[labels[column]] ||= Hash.new
- result[labels[column]][pair[0]] = v
- column += 1
- end
- end
+
+ result["starttime"] = times.first
+
+ # calculate the interval between elements
+ if times.size > 1
+ last = times.pop
+ times.each_with_index do |time, index|
+ result["interval"] = time.to_i - last.to_i
+ last = time
end
- result["interval"] = nexttime.to_i - result["starttime"].to_i if result["interval"].nil?
- return result
- else
- raise "error reading data from rrdtool"
end
+ return result
+
end
end
diff --git a/plugins/status/test/unit/metric_test.rb b/plugins/status/test/unit/metric_test.rb
index 867a638..7535ed2 100644
--- a/plugins/status/test/unit/metric_test.rb
+++ b/plugins/status/test/unit/metric_test.rb
@@ -2,7 +2,6 @@ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
require 'scr'
require 'mocha'
require 'metric'
-require 'test_helper'
def test_data(name)
File.join(File.dirname(__FILE__), '..', 'data', name)
@@ -41,46 +40,45 @@ class MetricTest < ActiveSupport::TestCase
memory = ret.first
expected = { "value"=>
- {"1252071700"=>"6.1514301440e+08",
- "1252071690"=>"6.1518643200e+08",
- "1252071680"=>"6.1513154560e+08",
- "1252071780"=>"invalid",
- "1252071670"=>"6.1510287360e+08",
- "1252071770"=>"invalid",
- "1252071660"=>"6.1664133120e+08",
- "1252071760"=>"6.1678837760e+08",
- "1252071750"=>"6.1545021440e+08"},
- "interval"=>10,
- "starttime"=>1252071660 }
+ {Time.at(1252071700) =>"6.1514301440e+08".to_f,
+ Time.at(1252071690) =>"6.1518643200e+08".to_f,
+ Time.at(1252071680) =>"6.1513154560e+08".to_f,
+ Time.at(1252071780) => nil,
+ Time.at(1252071670) =>"6.1510287360e+08".to_f,
+ Time.at(1252071770) => nil,
+ Time.at(1252071660) =>"6.1664133120e+08".to_f,
+ Time.at(1252071750) =>"6.1545021440e+08".to_f,
+ Time.at(1252071760) =>"6.1678837760e+08".to_f},
+
+ "interval" => 10,
+ "starttime" => Time.at(1252071660) }
assert_equal expected, memory.data(:start => start, :stop => stop)
ret = Metric.find(:all, :plugin => /interface/, :type => 'packets')
packets = ret.first
expected = {"tx"=>
- {"1252075780"=>"4.2576000000e+02",
- "1252075770"=>"1.5922000000e+02",
- "1252075760"=>"6.1660000000e+01",
- "1252075500"=>"7.7900000000e+00",
- "1252075800"=>"invalid",
- "1252075790"=>"invalid"},
+ {Time.at(1252075780) => "4.2576000000e+02".to_f,
+ Time.at(1252075770) => "1.5922000000e+02".to_f,
+ Time.at(1252075760) => "6.1660000000e+01".to_f,
+ Time.at(1252075500) => "7.7900000000e+00".to_f,
+ Time.at(1252075790) => nil,
+ Time.at(1252075800) => nil},
"rx"=>
- {"1252075780"=>"2.8069000000e+02",
- "1252075770"=>"3.3962000000e+02",
- "1252075760"=>"2.5814000000e+02",
- "1252075500"=>"2.2150000000e+01",
- "1252075800"=>"invalid",
- "1252075790"=>"invalid"},
- "interval"=>260,
- "starttime"=>1252075500}
+ {Time.at(1252075780) => "2.8069000000e+02".to_f,
+ Time.at(1252075770) => "3.3962000000e+02".to_f,
+ Time.at(1252075760) => "2.5814000000e+02".to_f,
+ Time.at(1252075500) => "2.2150000000e+01".to_f,
+ Time.at(1252075790) => nil,
+ Time.at(1252075800) => nil},
+ "interval"=>10,
+ "starttime"=>Time.at(1252075500)}
assert_equal expected, packets.data(:start => start, :stop => stop)
- require 'pp'
- pp packets.data(:start => start, :stop => stop)
+ xml = '<?xml version="1.0" encoding="UTF-8"?><metric><id>myhost.domain.de/interface/packets</id><host>myhost.domain.de</host><plugin>interface</plugin><type>packets</type><data interval="10" column="tx" start="1252075500"><value></value><value>425.76</value><value>159.22</value><value>61.66</value><value>7.79</value><value></value></data><data interval="10" column="rx" start="1252075500"><value></value><value>280.69</value><value>339.62</value><value>258.14</value><value>22.15</value><value></value></data></metric>'
- assert_equal "", packets.to_xml(:start => start, :stop => stop)
- #assert_equal "", packets.to_xml
+ assert_equal xml, packets.to_xml(:start => start, :stop => stop)
end
def test_collectd_running
--
To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org
For additional commands, e-mail: yast-commit+help@opensuse.org