daikon 0.7.4 → 0.7.5
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/daikon.gemspec +2 -3
- data/lib/daikon.rb +1 -2
- data/lib/daikon/client.rb +0 -53
- data/lib/daikon/monitor.rb +4 -1
- data/spec/client_spec.rb +2 -89
- data/spec/monitor_spec.rb +14 -0
- metadata +3 -4
- data/lib/daikon/namespace_tools.rb +0 -122
data/daikon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{daikon}
|
8
|
-
s.version = "0.7.
|
8
|
+
s.version = "0.7.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Nick Quaranto"]
|
12
|
-
s.date = %q{2011-02-
|
12
|
+
s.date = %q{2011-02-17}
|
13
13
|
s.default_executable = %q{daikon}
|
14
14
|
s.description = %q{daikon, a radishapp.com client}
|
15
15
|
s.email = %q{nick@quaran.to}
|
@@ -32,7 +32,6 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/daikon/configuration.rb",
|
33
33
|
"lib/daikon/daemon.rb",
|
34
34
|
"lib/daikon/monitor.rb",
|
35
|
-
"lib/daikon/namespace_tools.rb",
|
36
35
|
"lib/daikon/redis_hacks.rb",
|
37
36
|
"spec/client_spec.rb",
|
38
37
|
"spec/configuration_spec.rb",
|
data/lib/daikon.rb
CHANGED
@@ -18,7 +18,6 @@ $LOAD_PATH.unshift __DIR__ unless
|
|
18
18
|
$LOAD_PATH.include?(__DIR__) ||
|
19
19
|
$LOAD_PATH.include?(File.expand_path(__DIR__))
|
20
20
|
|
21
|
-
require 'daikon/namespace_tools'
|
22
21
|
require 'daikon/configuration'
|
23
22
|
require 'daikon/client'
|
24
23
|
require 'daikon/daemon'
|
@@ -26,5 +25,5 @@ require 'daikon/monitor'
|
|
26
25
|
require 'daikon/redis_hacks'
|
27
26
|
|
28
27
|
module Daikon
|
29
|
-
VERSION = "0.7.
|
28
|
+
VERSION = "0.7.5"
|
30
29
|
end
|
data/lib/daikon/client.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Daikon
|
2
2
|
class Client
|
3
|
-
include NamespaceTools
|
4
|
-
|
5
3
|
EXCEPTIONS = [Timeout::Error,
|
6
4
|
Errno::EINVAL,
|
7
5
|
Errno::ECONNRESET,
|
@@ -58,21 +56,6 @@ module Daikon
|
|
58
56
|
"Content-Type" => "application/json"})
|
59
57
|
end
|
60
58
|
|
61
|
-
def fetch_commands
|
62
|
-
raw_commands = request(:get, "/api/v1/commands.json")
|
63
|
-
commands = JSON.parse(raw_commands.body)
|
64
|
-
|
65
|
-
commands.each do |id, command|
|
66
|
-
result = evaluate_redis(command)
|
67
|
-
pretty = StringIO.new
|
68
|
-
PP.pp(result, pretty)
|
69
|
-
|
70
|
-
push :put, "/api/v1/commands/#{id}.json", {"response" => pretty.string.strip}
|
71
|
-
end
|
72
|
-
rescue *EXCEPTIONS => ex
|
73
|
-
exception(ex)
|
74
|
-
end
|
75
|
-
|
76
59
|
def rotate_monitor(start, stop)
|
77
60
|
payload = monitor.rotate.merge({
|
78
61
|
"start" => start,
|
@@ -89,41 +72,5 @@ module Daikon
|
|
89
72
|
rescue *EXCEPTIONS => ex
|
90
73
|
exception(ex)
|
91
74
|
end
|
92
|
-
|
93
|
-
def evaluate_redis(command)
|
94
|
-
# Attempt to parse the given command string.
|
95
|
-
argv =
|
96
|
-
begin
|
97
|
-
Shellwords.shellwords(command.to_s)
|
98
|
-
rescue Exception => e
|
99
|
-
exception(e)
|
100
|
-
return e.message
|
101
|
-
end
|
102
|
-
return "No command received." unless argv[0]
|
103
|
-
|
104
|
-
begin
|
105
|
-
execute_redis(argv)
|
106
|
-
rescue Exception => e
|
107
|
-
exception(e)
|
108
|
-
e.message
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def namespace
|
113
|
-
nil
|
114
|
-
end
|
115
|
-
|
116
|
-
def execute_redis(argv)
|
117
|
-
# Apply the current namespace to any fields that need it.
|
118
|
-
argv = namespace_input(namespace, *argv)
|
119
|
-
|
120
|
-
raise "Not a Redis command." unless argv.kind_of? Array
|
121
|
-
|
122
|
-
# Send the command to Redis.
|
123
|
-
result = redis.send(*argv)
|
124
|
-
|
125
|
-
# Remove the namespace from any commands that return a key.
|
126
|
-
denamespace_output namespace, argv.first, result
|
127
|
-
end
|
128
75
|
end
|
129
76
|
end
|
data/lib/daikon/monitor.rb
CHANGED
@@ -59,6 +59,9 @@ module Daikon
|
|
59
59
|
def push(raw_command)
|
60
60
|
command, key, *rest = raw_command.strip.gsub('"', '').split
|
61
61
|
command.upcase!
|
62
|
+
|
63
|
+
return unless ALL_COMMANDS.member?(command)
|
64
|
+
|
62
65
|
lock do
|
63
66
|
incr_command(command)
|
64
67
|
incr_total(command)
|
@@ -85,7 +88,7 @@ module Daikon
|
|
85
88
|
end
|
86
89
|
|
87
90
|
def incr_command(command)
|
88
|
-
data["commands"][command] += 1
|
91
|
+
data["commands"][command] += 1
|
89
92
|
end
|
90
93
|
|
91
94
|
def incr_key(key)
|
data/spec/client_spec.rb
CHANGED
@@ -37,72 +37,6 @@ describe Daikon::Client, "setup" do
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
shared_examples_for "a command api consumer" do
|
41
|
-
it "sends a request for commands" do
|
42
|
-
http.should have_received(:request).with(
|
43
|
-
:method => "GET",
|
44
|
-
:path => "/api/v1/commands.json",
|
45
|
-
:headers => {"Authorization" => api_key})
|
46
|
-
end
|
47
|
-
|
48
|
-
it "processes each command" do
|
49
|
-
subject.should have_received(:evaluate_redis).with("INCR foo")
|
50
|
-
subject.should have_received(:evaluate_redis).with("DECR foo")
|
51
|
-
end
|
52
|
-
|
53
|
-
it "shoots the results back to radish" do
|
54
|
-
results = {"response" => "9999"}.to_json
|
55
|
-
|
56
|
-
headers = {
|
57
|
-
"Authorization" => api_key,
|
58
|
-
"Content-Length" => results.size.to_s,
|
59
|
-
"Content-Type" => "application/json"
|
60
|
-
}
|
61
|
-
|
62
|
-
http.should have_received(:request).with(
|
63
|
-
:method => "PUT",
|
64
|
-
:path => "/api/v1/commands/42.json",
|
65
|
-
:body => results,
|
66
|
-
:headers => headers)
|
67
|
-
|
68
|
-
http.should have_received(:request).with(
|
69
|
-
:method => "PUT",
|
70
|
-
:path => "/api/v1/commands/43.json",
|
71
|
-
:body => results,
|
72
|
-
:headers => headers)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe Daikon::Client, "fetching commands" do
|
77
|
-
subject { Daikon::Client.new }
|
78
|
-
let(:body) { {"42" => "INCR foo", "43" => "DECR foo"}.to_json }
|
79
|
-
let(:http) { stub("http", :request => Excon::Response.new(:body => body)) }
|
80
|
-
|
81
|
-
before do
|
82
|
-
subject.stubs(:evaluate_redis => 9999)
|
83
|
-
subject.stubs(:http => http)
|
84
|
-
|
85
|
-
subject.setup(config)
|
86
|
-
subject.fetch_commands
|
87
|
-
end
|
88
|
-
|
89
|
-
context "with default configuration" do
|
90
|
-
let(:api_key) { config.api_key }
|
91
|
-
let(:server) { "https://radish.heroku.com" }
|
92
|
-
let(:config) { Daikon::Configuration.new([]) }
|
93
|
-
|
94
|
-
it_should_behave_like "a command api consumer"
|
95
|
-
end
|
96
|
-
|
97
|
-
context "with custom settings" do
|
98
|
-
let(:api_key) { "0987654321" }
|
99
|
-
let(:server) { "http://localhost:9999" }
|
100
|
-
let(:config) { Daikon::Configuration.new(["-k", api_key, "-s", "http://localhost:9999"]) }
|
101
|
-
|
102
|
-
it_should_behave_like "a command api consumer"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
40
|
describe Daikon::Client, "when server is down" do
|
107
41
|
subject { Daikon::Client.new }
|
108
42
|
before do
|
@@ -114,7 +48,7 @@ describe Daikon::Client, "when server is down" do
|
|
114
48
|
|
115
49
|
it "does not commit suicide" do
|
116
50
|
lambda {
|
117
|
-
subject.
|
51
|
+
subject.report_info
|
118
52
|
}.should_not raise_error
|
119
53
|
end
|
120
54
|
end
|
@@ -129,7 +63,7 @@ describe Daikon::Client, "when it returns bad json" do
|
|
129
63
|
|
130
64
|
it "does not commit suicide" do
|
131
65
|
lambda {
|
132
|
-
subject.
|
66
|
+
subject.report_info
|
133
67
|
}.should_not raise_error
|
134
68
|
end
|
135
69
|
end
|
@@ -194,27 +128,6 @@ describe Daikon::Client, "rotate monitor" do
|
|
194
128
|
end
|
195
129
|
end
|
196
130
|
|
197
|
-
describe Daikon::Client, "pretty printing results" do
|
198
|
-
subject { Daikon::Client.new }
|
199
|
-
let(:body) { {"13" => "LRANGE foo 0 -1"}.to_json }
|
200
|
-
let(:list) { %w[apples bananas carrots] }
|
201
|
-
let(:server) { "https://radish.heroku.com" }
|
202
|
-
let(:config) { Daikon::Configuration.new }
|
203
|
-
let(:http) { stub("http", :request => Excon::Response.new(:body => body)) }
|
204
|
-
|
205
|
-
before do
|
206
|
-
subject.stubs(:evaluate_redis => list, :http => http)
|
207
|
-
subject.setup(config)
|
208
|
-
subject.fetch_commands
|
209
|
-
end
|
210
|
-
|
211
|
-
it "returns pretty printed results" do
|
212
|
-
http.should have_received(:request).with(has_entry(
|
213
|
-
:body => {"response" => "[\"apples\", \"bananas\", \"carrots\"]"}.to_json
|
214
|
-
))
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
131
|
shared_examples_for "a info api consumer" do
|
219
132
|
it "shoots the results back to radish" do
|
220
133
|
headers = {
|
data/spec/monitor_spec.rb
CHANGED
@@ -160,3 +160,17 @@ describe Daikon::Monitor, "#rotate that collects namespaces" do
|
|
160
160
|
data["namespaces"]["s3"].should == 1
|
161
161
|
end
|
162
162
|
end
|
163
|
+
|
164
|
+
describe Daikon::Monitor, "#rotate with values that have spaces" do
|
165
|
+
before do
|
166
|
+
subject.parse("set g:2470920:mrn 11")
|
167
|
+
subject.parse("Email Error")
|
168
|
+
end
|
169
|
+
|
170
|
+
it "keeps track of namespace accesses" do
|
171
|
+
data = subject.rotate
|
172
|
+
data["commands"].should == {"SET" => 1}
|
173
|
+
data["keys"].should == {"g:2470920:mrn" => 1}
|
174
|
+
data["namespaces"].should == {"g" => 1}
|
175
|
+
end
|
176
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
8
|
+
- 5
|
9
|
+
version: 0.7.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nick Quaranto
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-02-
|
17
|
+
date: 2011-02-17 00:00:00 -05:00
|
18
18
|
default_executable: daikon
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -165,7 +165,6 @@ files:
|
|
165
165
|
- lib/daikon/configuration.rb
|
166
166
|
- lib/daikon/daemon.rb
|
167
167
|
- lib/daikon/monitor.rb
|
168
|
-
- lib/daikon/namespace_tools.rb
|
169
168
|
- lib/daikon/redis_hacks.rb
|
170
169
|
- spec/client_spec.rb
|
171
170
|
- spec/configuration_spec.rb
|
@@ -1,122 +0,0 @@
|
|
1
|
-
module Daikon
|
2
|
-
module NamespaceTools
|
3
|
-
def namespace_input(ns, command, *args)
|
4
|
-
command = command.to_s.downcase
|
5
|
-
|
6
|
-
case command
|
7
|
-
|
8
|
-
when "multi", "exec", "discard"
|
9
|
-
|
10
|
-
# No arguments.
|
11
|
-
|
12
|
-
[ command ]
|
13
|
-
|
14
|
-
when "exists", "del", "type", "keys", "ttl", "set", "get", "getset",
|
15
|
-
"setnx", "incr", "incrby", "decr", "decrby", "rpush", "lpush",
|
16
|
-
"llen", "lrange", "ltrim", "lindex", "lset", "lrem", "lpop", "rpop",
|
17
|
-
"sadd", "srem", "spop", "scard", "sismember", "smembers", "srandmember",
|
18
|
-
"zadd", "zrem", "zincrby", "zrange", "zrevrange", "zrangebyscore",
|
19
|
-
"zcard", "zscore", "zremrangebyscore", "expire", "expireat", "hlen",
|
20
|
-
"hkeys", "hvals", "hgetall", "hset", "hget", "hincrby", "hexists",
|
21
|
-
"hdel", "hmset"
|
22
|
-
|
23
|
-
# Only the first argument is a key.
|
24
|
-
|
25
|
-
head = add_namespace(ns, args.first)
|
26
|
-
tail = args[1, args.length - 1] || []
|
27
|
-
|
28
|
-
[ command, head, *tail ]
|
29
|
-
|
30
|
-
when "smove"
|
31
|
-
|
32
|
-
# The first two parmeters are keys.
|
33
|
-
|
34
|
-
result = [ command ]
|
35
|
-
|
36
|
-
args.each_with_index do |arg, i|
|
37
|
-
result << ((i == 0 || i == 1) ? add_namespace(ns, arg) : arg)
|
38
|
-
end
|
39
|
-
|
40
|
-
result
|
41
|
-
|
42
|
-
when "mget", "rpoplpush", "sinter", "sunion", "sdiff", "info",
|
43
|
-
"sinterstore", "sunionstore", "sdiffstore", "dbsize"
|
44
|
-
|
45
|
-
# All arguments are keys.
|
46
|
-
|
47
|
-
keys = add_namespace(ns, args)
|
48
|
-
|
49
|
-
[ command, *keys ]
|
50
|
-
|
51
|
-
when "mset", "msetnx"
|
52
|
-
|
53
|
-
# Every other argument is a key, starting with the first.
|
54
|
-
|
55
|
-
hash1 = Hash[*args]
|
56
|
-
hash2 = {}
|
57
|
-
|
58
|
-
hash1.each do |k, v|
|
59
|
-
hash2[add_namespace(ns, k)] = hash1.delete(k)
|
60
|
-
end
|
61
|
-
|
62
|
-
[ command, hash2 ]
|
63
|
-
|
64
|
-
when "sort"
|
65
|
-
|
66
|
-
return [] if args.count == 0
|
67
|
-
|
68
|
-
key = add_namespace(ns, args.shift)
|
69
|
-
parms = {}
|
70
|
-
|
71
|
-
while keyword = args.shift.andand.downcase
|
72
|
-
case keyword
|
73
|
-
when "by", "get", "store"
|
74
|
-
k = keyword.intern
|
75
|
-
v = add_namespace(ns, args.shift)
|
76
|
-
|
77
|
-
parms[k] = v
|
78
|
-
when "limit"
|
79
|
-
parms[:limit] = [ args.shift.to_i, args.shift.to_i ]
|
80
|
-
when "asc", "desc", "alpha"
|
81
|
-
parms[:order].andand << " "
|
82
|
-
parms[:order] ||= ""
|
83
|
-
parms[:order] << keyword
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
[ command, key, parms ]
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def denamespace_output(namespace, command, result)
|
93
|
-
case command.to_s.downcase
|
94
|
-
|
95
|
-
when "keys"
|
96
|
-
remove_namespace namespace, result
|
97
|
-
|
98
|
-
else
|
99
|
-
result
|
100
|
-
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def add_namespace(namespace, key)
|
105
|
-
return key unless namespace
|
106
|
-
|
107
|
-
case key
|
108
|
-
when String then "#{namespace}:#{key}"
|
109
|
-
when Array then key.map {|k| add_namespace(namespace, k)}
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def remove_namespace(namespace, key)
|
114
|
-
return key unless namespace
|
115
|
-
|
116
|
-
case key
|
117
|
-
when String then key.gsub(/^#{namespace}:/, "")
|
118
|
-
when Array then key.map {|k| remove_namespace(namespace, k)}
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|