absperf-collectd_server 0.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.
- 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
|