absperf-collectd_server 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +7 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/bin/collectd_server +4 -0
- data/lib/collectd_server.rb +70 -0
- data/lib/collectd_server/datapoint.rb +22 -0
- data/lib/collectd_server/datapoint_builder.rb +142 -0
- data/lib/collectd_server/mapper.rb +87 -0
- data/lib/collectd_server/packet.rb +188 -0
- data/lib/collectd_server/ssbe_authenticator.rb +50 -0
- data/spec/collectd_server_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- metadata +88 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Paul Sadauskas
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "collectd_server"
|
8
|
+
gem.summary = %Q{TODO}
|
9
|
+
gem.email = "psadauskas@gmail.com"
|
10
|
+
gem.homepage = "http://github.com/paul/collectd_server"
|
11
|
+
gem.authors = ["Paul Sadauskas"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
|
14
|
+
gem.add_dependency 'resourceful', '~> 0.5.0'
|
15
|
+
gem.add_dependency 'fastercsv', '~> 1.4.0'
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'spec/rake/spectask'
|
24
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
25
|
+
spec.libs << 'lib' << 'spec'
|
26
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
end
|
28
|
+
|
29
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
32
|
+
spec.rcov = true
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
if File.exist?('VERSION.yml')
|
41
|
+
config = YAML.load(File.read('VERSION.yml'))
|
42
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
43
|
+
else
|
44
|
+
version = ""
|
45
|
+
end
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "collectd_server #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
52
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
data/bin/collectd_server
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'socket'
|
4
|
+
require 'resourceful'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
require File.dirname(__FILE__) + '/collectd_server/packet'
|
8
|
+
require File.dirname(__FILE__) + '/collectd_server/ssbe_authenticator'
|
9
|
+
|
10
|
+
PREVIOUS_VALUES = {}
|
11
|
+
|
12
|
+
module CollectdServer
|
13
|
+
|
14
|
+
class Runner
|
15
|
+
|
16
|
+
attr_accessor :port
|
17
|
+
|
18
|
+
def initialize(port = 1981, services = 'http://auth.v6.localhost/services')
|
19
|
+
@port = port
|
20
|
+
@services = services
|
21
|
+
end
|
22
|
+
|
23
|
+
def run!
|
24
|
+
@socket = UDPSocket.new
|
25
|
+
@socket.bind(nil, port)
|
26
|
+
@connection = Connection.new(@services)
|
27
|
+
loop do
|
28
|
+
data = @socket.recvfrom(65535)
|
29
|
+
@connection.receive_data(data.first)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
class Connection
|
37
|
+
|
38
|
+
def initialize(service_uri)
|
39
|
+
@http = Resourceful::HttpAccessor.new
|
40
|
+
@http.add_authenticator(Resourceful::SSBEAuthenticator.new('admin', 'admin'))
|
41
|
+
resp = @http.resource(service_uri).get(:accept => 'application/csv')
|
42
|
+
|
43
|
+
bulk_datapoint_href = nil
|
44
|
+
FasterCSV.parse(resp.body, :headers => true) do |row|
|
45
|
+
if row['name'] == 'BulkCreateDatapoints'
|
46
|
+
bulk_datapoint_href = row['resource_href']
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
@datapoint_resource = @http.resource(bulk_datapoint_href)
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def receive_data(data)
|
55
|
+
packet = Packet.new(data)
|
56
|
+
dps = packet.to_datapoints
|
57
|
+
|
58
|
+
csv = FasterCSV.generate do |csv|
|
59
|
+
dps.each do |dp|
|
60
|
+
csv << dp.to_a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
@datapoint_resource.post(csv, :content_type => 'text/csv')
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'fastercsv'
|
2
|
+
|
3
|
+
module CollectdServer
|
4
|
+
|
5
|
+
class Datapoint
|
6
|
+
attr_reader :metric_name, :timestamp, :value
|
7
|
+
|
8
|
+
def initialize(name, timestamp, value)
|
9
|
+
@metric_name, @timestamp, @value = name, timestamp, value
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_csv
|
13
|
+
to_a.to_csv
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_a
|
17
|
+
[metric_name, timestamp, value]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'fastercsv'
|
2
|
+
require 'tempfile'
|
3
|
+
require File.dirname(__FILE__) + '/datapoint'
|
4
|
+
|
5
|
+
module CollectdServer
|
6
|
+
|
7
|
+
class DatapointBuilder
|
8
|
+
def self.from_parts(parts, values)
|
9
|
+
begin
|
10
|
+
plugin_name = parts.detect { |p| p.is_a?(Packet::Plugin) }.content
|
11
|
+
rescue NoMethodError => e
|
12
|
+
puts "failed to find plugin part of #{parts.inspect}"
|
13
|
+
return []
|
14
|
+
#raise e
|
15
|
+
end
|
16
|
+
|
17
|
+
builder = subclasses.detect { |c| c.plugin_name == plugin_name }
|
18
|
+
|
19
|
+
if builder
|
20
|
+
builder.new(parts, values)
|
21
|
+
else
|
22
|
+
warn "No builder found for plugin '#{plugin_name}'. Using default"
|
23
|
+
self.new(parts, values)
|
24
|
+
end.generate_datapoints
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :parts, :values,
|
28
|
+
:interval, :timestamp,
|
29
|
+
:host, :plugin, :plugin_instance,
|
30
|
+
:type, :type_instance
|
31
|
+
|
32
|
+
def initialize(parts, values)
|
33
|
+
@parts = parts.dup
|
34
|
+
parts.each do |part|
|
35
|
+
next if part.content == ""
|
36
|
+
case part
|
37
|
+
when Packet::Host then @host = part.content
|
38
|
+
when Packet::Time then @timestamp = part.content
|
39
|
+
when Packet::Interval then @interval = part.content
|
40
|
+
when Packet::Plugin then @plugin = part.content
|
41
|
+
when Packet::PluginInstance then @plugin_instance = part.content
|
42
|
+
when Packet::Type then @type = part.content
|
43
|
+
when Packet::TypeInstance then @type_instance = part.content
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@values = values
|
48
|
+
end
|
49
|
+
|
50
|
+
def generate_datapoints
|
51
|
+
@values.values.map do |val|
|
52
|
+
Datapoint.new(metric_name, timestamp, val.value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def metric_name(parts = nil)
|
57
|
+
parts ||= [@host, @plugin, @plugin_instance, @type, @type_instance]
|
58
|
+
parts.compact.to_csv.chomp
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.subclasses
|
62
|
+
@subclasses ||= []
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.inherited(subclass)
|
66
|
+
subclasses << subclass
|
67
|
+
end
|
68
|
+
|
69
|
+
class CPU < DatapointBuilder
|
70
|
+
|
71
|
+
def self.plugin_name
|
72
|
+
'cpu'
|
73
|
+
end
|
74
|
+
|
75
|
+
def metric_name
|
76
|
+
super [@host, @plugin, @plugin_instance, @type_instance, 'jiffies/s']
|
77
|
+
end
|
78
|
+
|
79
|
+
def generate_datapoints
|
80
|
+
current_value = @values.values.first.value
|
81
|
+
datapoints = []
|
82
|
+
unless previous_value.nil?
|
83
|
+
delta = current_value - previous_value
|
84
|
+
rate = delta.to_f / interval
|
85
|
+
datapoints = [Datapoint.new(metric_name, timestamp, rate)]
|
86
|
+
end
|
87
|
+
|
88
|
+
self.previous_value = current_value
|
89
|
+
|
90
|
+
datapoints
|
91
|
+
end
|
92
|
+
|
93
|
+
def previous_value
|
94
|
+
@previous_value ||= PREVIOUS_VALUES[metric_name]
|
95
|
+
end
|
96
|
+
|
97
|
+
def previous_value=(value)
|
98
|
+
PREVIOUS_VALUES[metric_name] = value
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class LoadAvg < DatapointBuilder
|
105
|
+
|
106
|
+
def self.plugin_name
|
107
|
+
'load'
|
108
|
+
end
|
109
|
+
|
110
|
+
def generate_datapoints
|
111
|
+
datapoints = []
|
112
|
+
@values.values.each_with_index do |val, i|
|
113
|
+
instance = case i
|
114
|
+
when 0 then "1min"
|
115
|
+
when 1 then "5min"
|
116
|
+
when 2 then "15min"
|
117
|
+
end
|
118
|
+
|
119
|
+
datapoints << Datapoint.new(metric_name([@host, "load", instance]),
|
120
|
+
timestamp,
|
121
|
+
val.value)
|
122
|
+
end
|
123
|
+
datapoints
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
class Memory < DatapointBuilder
|
129
|
+
|
130
|
+
def self.plugin_name
|
131
|
+
'memory'
|
132
|
+
end
|
133
|
+
|
134
|
+
def metric_name
|
135
|
+
super [@host, @plugin, @type_instance, "Bytes"]
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
|
2
|
+
module CollectdServer
|
3
|
+
|
4
|
+
class Mapper
|
5
|
+
attr_reader :metric_name, :timestamp, :value
|
6
|
+
|
7
|
+
def self.parse(line)
|
8
|
+
if klass = mapper_class(line)
|
9
|
+
klass.parse(line)
|
10
|
+
else
|
11
|
+
warn "No Mapper found for '#{line}'"
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(metric_name, timestamp, value)
|
17
|
+
@metric_name, @timestamp, @value = metric_name, timestamp, value
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_datapoint
|
21
|
+
%Q{"#{@metric_name}",#{@timestamp},#{@value}}
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def self.mapper_class(line)
|
27
|
+
self.subclasses.detect { |c| c.matches?(line) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.plugin_name(line)
|
31
|
+
_, collectd_type, *_ = line.split
|
32
|
+
collectd_type.split('/')[1]
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parse_line(line)
|
36
|
+
_, path, _, data = line.split(' ')
|
37
|
+
timestamp, *values = data.split(':')
|
38
|
+
|
39
|
+
return path, timestamp, values
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.metric_name_from_type(collectd_type)
|
43
|
+
@parts = collectd_type.split('/')
|
44
|
+
|
45
|
+
@host = @parts[0]
|
46
|
+
@plugin, @plugin_instance = @parts[1].split('-')
|
47
|
+
@type, @type_instance = @parts[2].split('-')
|
48
|
+
|
49
|
+
return [@host, @plugin, @plugin_instance, @type, @type_instance].join(',')
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.subclasses
|
53
|
+
@subclasses ||= []
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.inherited(subclass)
|
57
|
+
subclasses << subclass
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
class CPU < Mapper
|
63
|
+
|
64
|
+
def self.matches?(line)
|
65
|
+
plugin_name(line) =~ /cpu-[\d+]/
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.parse(line)
|
69
|
+
path, timestamp, values = parse_line(line)
|
70
|
+
|
71
|
+
metric_name = metric_name_from_type(path)
|
72
|
+
values.map do |val|
|
73
|
+
self.new(metric_name, timestamp, val)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.metric_name_from_type(collectd_type)
|
78
|
+
super
|
79
|
+
|
80
|
+
# apollo, cpu, 0, idle
|
81
|
+
[@host, @plugin, @plugin_instance, @type_instance].join(',')
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
@@ -0,0 +1,188 @@
|
|
1
|
+
|
2
|
+
require File.dirname(__FILE__) + '/datapoint_builder'
|
3
|
+
|
4
|
+
module CollectdServer
|
5
|
+
|
6
|
+
class Packet
|
7
|
+
attr_reader :parts
|
8
|
+
|
9
|
+
def initialize(data)
|
10
|
+
@parts = []
|
11
|
+
data = data.dup # don't modify the data passed in
|
12
|
+
while !data.empty?
|
13
|
+
type, length = data.slice!(0,4).unpack('nn')
|
14
|
+
content_length = length - 4
|
15
|
+
content = data.slice!(0, content_length)
|
16
|
+
|
17
|
+
@parts << Part.class_for(type).new(content)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_datapoints
|
22
|
+
datapoints = []
|
23
|
+
stack = Stack.new
|
24
|
+
|
25
|
+
@parts.each do |part|
|
26
|
+
|
27
|
+
if part.is_a?(Values) # Values is the last "part"
|
28
|
+
datapoints += DatapointBuilder.from_parts(stack.to_a, part)
|
29
|
+
else
|
30
|
+
stack.update_part(part)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
datapoints
|
35
|
+
end
|
36
|
+
|
37
|
+
class Stack
|
38
|
+
|
39
|
+
ORDER = [:host, :time, :interval, :plugin, :plugin_instance, :type, :type_instance]
|
40
|
+
|
41
|
+
def initialize
|
42
|
+
@stack = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_part(part)
|
46
|
+
name = part_name(part)
|
47
|
+
|
48
|
+
@stack[name] = part
|
49
|
+
end
|
50
|
+
|
51
|
+
def part_name(part)
|
52
|
+
case part
|
53
|
+
when Packet::Host then :host
|
54
|
+
when Packet::Time then :time
|
55
|
+
when Packet::Interval then :interval
|
56
|
+
when Packet::Plugin then :plugin
|
57
|
+
when Packet::PluginInstance then :plugin_instance
|
58
|
+
when Packet::Type then :type
|
59
|
+
when Packet::TypeInstance then :type_instance
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_a
|
64
|
+
ORDER.map{ |field| @stack[field] }.compact
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
class Part
|
70
|
+
|
71
|
+
attr_reader :content
|
72
|
+
|
73
|
+
def self.type(number)
|
74
|
+
define_method(:type) { number }
|
75
|
+
Part.add_type(self, number)
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.add_type(klass, number)
|
79
|
+
@types ||= {}
|
80
|
+
@types[number] = klass
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.part_for(type, content)
|
84
|
+
if klass = self.class_for(type)
|
85
|
+
klass.new(content)
|
86
|
+
else
|
87
|
+
warn "Unrecognized type %x" % type
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.class_for(type)
|
92
|
+
@types[type]
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize(content)
|
96
|
+
@content = content
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
class String < Part
|
102
|
+
def initialize(content)
|
103
|
+
@content = content[0..-2] # strip off the null byte at the end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Number < Part
|
108
|
+
def initialize(content)
|
109
|
+
big, small = content.unpack('NN')
|
110
|
+
@content = (big << 32) + (small)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Host < String
|
115
|
+
type 0
|
116
|
+
end
|
117
|
+
|
118
|
+
class Time < Number
|
119
|
+
type 1
|
120
|
+
end
|
121
|
+
|
122
|
+
class Plugin < String
|
123
|
+
type 2
|
124
|
+
end
|
125
|
+
|
126
|
+
class PluginInstance < String
|
127
|
+
type 3
|
128
|
+
end
|
129
|
+
|
130
|
+
class Type < String
|
131
|
+
type 4
|
132
|
+
end
|
133
|
+
|
134
|
+
class TypeInstance < String
|
135
|
+
type 5
|
136
|
+
end
|
137
|
+
|
138
|
+
class Values < Part
|
139
|
+
type 6
|
140
|
+
|
141
|
+
attr_reader :values
|
142
|
+
|
143
|
+
def initialize(content)
|
144
|
+
size = content.slice!(0,2).unpack('n').first
|
145
|
+
types = []
|
146
|
+
size.times { types << content.slice!(0,1).unpack("C").first }
|
147
|
+
@values = []
|
148
|
+
size.times do |i|
|
149
|
+
@values << Value.new_for_type(types[i], content.slice!(0,8))
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class Value
|
154
|
+
attr_reader :value
|
155
|
+
|
156
|
+
def self.new_for_type(type, content)
|
157
|
+
if type == 0
|
158
|
+
Counter.new(content)
|
159
|
+
elsif type == 1
|
160
|
+
Gauge.new(content)
|
161
|
+
else
|
162
|
+
raise "Unknown value type #{type}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Counter < Value
|
168
|
+
def initialize(content)
|
169
|
+
big, small = content.unpack('NN')
|
170
|
+
@value = (big << 32) + (small)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class Gauge < Value
|
175
|
+
def initialize(content)
|
176
|
+
@value = content.unpack('d').first
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class Interval < Number
|
182
|
+
type 7
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Resourceful
|
2
|
+
|
3
|
+
class SSBEAuthenticator
|
4
|
+
require 'httpauth'
|
5
|
+
require 'addressable/uri'
|
6
|
+
|
7
|
+
|
8
|
+
attr_reader :username, :password, :realm, :domain, :challenge
|
9
|
+
|
10
|
+
def initialize(username, password)
|
11
|
+
@username, @password = username, password
|
12
|
+
@realm = 'SystemShepherd'
|
13
|
+
@domain = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def update_credentials(challenge_response)
|
17
|
+
@domain = Addressable::URI.parse(challenge_response.uri).host
|
18
|
+
@challenge = HTTPAuth::Digest::Challenge.from_header(challenge_response.header['WWW-Authenticate'].first)
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid_for?(challenge_response)
|
22
|
+
return false unless challenge_header = challenge_response.header['WWW-Authenticate']
|
23
|
+
begin
|
24
|
+
challenge = HTTPAuth::Digest::Challenge.from_header(challenge_header.first)
|
25
|
+
rescue HTTPAuth::UnwellformedHeader
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
challenge.realm == @realm
|
29
|
+
end
|
30
|
+
|
31
|
+
def can_handle?(request)
|
32
|
+
Addressable::URI.parse(request.uri).host == @domain
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_credentials_to(request)
|
36
|
+
request.header['Authorization'] = credentials_for(request)
|
37
|
+
end
|
38
|
+
|
39
|
+
def credentials_for(request)
|
40
|
+
HTTPAuth::Digest::Credentials.from_challenge(@challenge,
|
41
|
+
:username => @username,
|
42
|
+
:password => @password,
|
43
|
+
:method => request.method.to_s.upcase,
|
44
|
+
:uri => Addressable::URI.parse(request.uri).path).to_header
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: absperf-collectd_server
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Sadauskas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-11 00:00:00 -07:00
|
13
|
+
default_executable: collectd_server
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: resourceful
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.5.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: fastercsv
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.4.0
|
34
|
+
version:
|
35
|
+
description:
|
36
|
+
email: psadauskas@gmail.com
|
37
|
+
executables:
|
38
|
+
- collectd_server
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- bin/collectd_server
|
52
|
+
- lib/collectd_server.rb
|
53
|
+
- lib/collectd_server/datapoint.rb
|
54
|
+
- lib/collectd_server/datapoint_builder.rb
|
55
|
+
- lib/collectd_server/mapper.rb
|
56
|
+
- lib/collectd_server/packet.rb
|
57
|
+
- lib/collectd_server/ssbe_authenticator.rb
|
58
|
+
- spec/collectd_server_spec.rb
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
has_rdoc: false
|
61
|
+
homepage: http://github.com/paul/collectd_server
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options:
|
64
|
+
- --charset=UTF-8
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.2.0
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: TODO
|
86
|
+
test_files:
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/collectd_server_spec.rb
|