quark 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/quark CHANGED
@@ -7,28 +7,24 @@ module Quark
7
7
  class CLI
8
8
  class<<self
9
9
  def run()
10
- Quark::Config.set("quark.address", "127.0.0.1")
11
- Quark::Config.set("quark.port", 12161)
12
- Quark::Config.set("quark.blocksize", 3600000)
13
- Quark::Config.set("quark.udp.enabled", false)
14
- Quark::Config.set("quark.graphite_compat", true)
15
- Quark::Config.set("debug", false)
10
+ # sets default options
11
+ Quark::Server.setup()
16
12
 
17
13
  (OptionParser.new do |opts|
18
14
  opts.banner = "Usage: quark [options]"
19
15
 
20
16
  # -----------------------------------------------------------------------------
21
- opts.on('-H', '--redis-host HOST', 'Hostname of the Redis server to write to') do |host|
17
+ opts.on('', '--redis-host HOST', 'Hostname of the Redis server to write to') do |host|
22
18
  Quark::Config.set("redis.host", host)
23
19
  end
24
20
 
25
21
  # -----------------------------------------------------------------------------
26
- opts.on('-P', '--redis-port PORT', 'Hostname of the Redis server to write to') do |port|
22
+ opts.on('', '--redis-port PORT', 'Hostname of the Redis server to write to') do |port|
27
23
  Quark::Config.set("redis.port", port)
28
24
  end
29
25
 
30
26
  # -----------------------------------------------------------------------------
31
- opts.on('-N', '--redis-prefix PREFIX', 'The string used to prefix keys in Redis') do |prefix|
27
+ opts.on('', '--redis-prefix PREFIX', 'The string used to prefix keys in Redis') do |prefix|
32
28
  Quark::Config.set("redis.prefix", prefix)
33
29
  end
34
30
 
@@ -38,12 +34,12 @@ module Quark
38
34
  end
39
35
 
40
36
  # -----------------------------------------------------------------------------
41
- opts.on('-a', '--tcp-address ADDR', 'The IP address for the TCP server to listen on') do |addr|
37
+ opts.on('-a', '--address ADDR', 'The IP address for the TCP server to listen on') do |addr|
42
38
  Quark::Config.set("quark.address", addr)
43
39
  end
44
40
 
45
41
  # -----------------------------------------------------------------------------
46
- opts.on('-p', '--tcp-port PORT', 'The TCP port to listen on') do |port|
42
+ opts.on('-p', '--port PORT', 'The TCP port to listen on') do |port|
47
43
  Quark::Config.set("quark.port", port)
48
44
  end
49
45
 
@@ -53,13 +49,23 @@ module Quark
53
49
  end
54
50
 
55
51
  # -----------------------------------------------------------------------------
56
- opts.on('-U', '--udp', 'Create a UDP server') do
57
- Quark::Config.set("quark.udp.enabled", true)
52
+ opts.on('-T', '--[no-]tcp', 'Create a TCP server') do |mode|
53
+ Quark::Config.set("quark.tcp.enabled", mode)
58
54
  end
59
55
 
60
56
  # -----------------------------------------------------------------------------
61
- opts.on('-D', '--debug', 'Enable debug mode') do
62
- Quark::Config.set("debug", true)
57
+ opts.on('', '--tcp-address ADDR', 'The IP address for the TCP server to listen on') do |addr|
58
+ Quark::Config.set("quark.tcp.address", addr)
59
+ end
60
+
61
+ # -----------------------------------------------------------------------------
62
+ opts.on('', '--tcp-port PORT', 'The TCP port to listen on') do |port|
63
+ Quark::Config.set("quark.tcp.port", port)
64
+ end
65
+
66
+ # -----------------------------------------------------------------------------
67
+ opts.on('-U', '--[no-]udp', 'Create a UDP server') do |mode|
68
+ Quark::Config.set("quark.udp.enabled", mode)
63
69
  end
64
70
 
65
71
  # -----------------------------------------------------------------------------
@@ -74,6 +80,25 @@ module Quark
74
80
  Quark::Config.set("quark.udp.port", port)
75
81
  end
76
82
 
83
+ # -----------------------------------------------------------------------------
84
+ opts.on('-H', '--[no-]http', 'Create an HTTP server') do |mode|
85
+ Quark::Config.set("quark.http.enabled", mode)
86
+ end
87
+
88
+ # -----------------------------------------------------------------------------
89
+ opts.on('', '--http-address ADDR', 'The IP address for the HTTP server to listen on') do |addr|
90
+ Quark::Config.set("quark.http.address", addr)
91
+ end
92
+
93
+ # -----------------------------------------------------------------------------
94
+ opts.on('', '--http-port PORT', 'The HTTP port to listen on') do |port|
95
+ Quark::Config.set("quark.http.port", port)
96
+ end
97
+
98
+ # -----------------------------------------------------------------------------
99
+ opts.on('-D', '--debug', 'Enable debug mode') do
100
+ Quark::Config.set("debug", true)
101
+ end
77
102
 
78
103
  # -----------------------------------------------------------------------------
79
104
  opts.on('', '--[no-]graphite', 'Enable/disable Graphite socket compatibility mode') do |mode|
data/lib/quark.rb CHANGED
@@ -5,6 +5,7 @@ require 'hiredis'
5
5
  require 'em-synchrony'
6
6
  require 'multi_json'
7
7
  require 'quark/config'
8
+ require 'quark/servers/http'
8
9
 
9
10
 
10
11
  module Quark
@@ -28,6 +29,14 @@ module Quark
28
29
  end
29
30
 
30
31
  def receive_data(data)
32
+ send_json(Quark::SocketServer.process_command(data))
33
+ end
34
+
35
+ def send_json(data)
36
+ send_data(MultiJson.dump(data)+"\n")
37
+ end
38
+
39
+ def self.process_command(data)
31
40
  # if the data perfectly resembles a graphite-formatted metric (without a command prefix)
32
41
  # then assume the command is "observe"
33
42
  if Quark::Config.get("quark.graphite_compat") and data =~ /^[\w\.\-]+ -?[\d\.]+ \d{10,13}$/
@@ -41,32 +50,32 @@ module Quark
41
50
  if methods.include?(:"process_command_#{command.downcase}")
42
51
  rv = send(:"process_command_#{command.downcase}", arguments)
43
52
  if rv.nil?
44
- send_json({
53
+ return {
45
54
  :success => true
46
- })
55
+ }
47
56
  else
48
- send_json({
57
+ return {
49
58
  :success => true,
50
59
  :command => data.chomp,
51
60
  :results => rv
52
- })
61
+ }
53
62
  end
54
63
  else
55
64
  raise Quark::InvalidCommand.new("Unknown command '#{command.upcase}'")
56
65
  end
57
66
 
58
67
  rescue Quark::Error => e
59
- send_json({
68
+ return {
60
69
  :success => false,
61
70
  :command => data.chomp,
62
71
  :error => {
63
72
  :class => e.class.name,
64
73
  :message => e.message
65
74
  }
66
- })
75
+ }
67
76
 
68
77
  rescue Exception => e
69
- send_json({
78
+ return {
70
79
  :success => false,
71
80
  :command => data.chomp,
72
81
  :error => {
@@ -74,34 +83,48 @@ module Quark
74
83
  :message => e.message,
75
84
  :backtrace => e.backtrace
76
85
  }
77
- })
86
+ }
78
87
  end
79
88
  end
80
89
 
81
- def send_json(data)
82
- send_data(MultiJson.dump(data)+"\n")
83
- end
84
-
85
90
  def unbind()
86
91
  end
87
92
  end
88
93
 
89
94
  class Server
95
+ def self.setup()
96
+ Quark::Config.set("quark.address", "127.0.0.1")
97
+ Quark::Config.set("quark.port", 12161)
98
+ Quark::Config.set("quark.blocksize", 3600000)
99
+ Quark::Config.set("quark.tcp.enabled", true)
100
+ Quark::Config.set("quark.udp.enabled", false)
101
+ Quark::Config.set("quark.http.enabled", false)
102
+ Quark::Config.set("quark.http.port", 12180)
103
+ Quark::Config.get("quark.http.cors", false)
104
+ Quark::Config.set("quark.graphite_compat", true)
105
+ Quark::Config.set("debug", false)
106
+ end
107
+
90
108
  def self.run()
91
109
  @address = Quark::Config.get("quark.address")
92
110
  @port = Quark::Config.get("quark.port")
93
111
  @filename = Quark::Config.get("quark.socket")
94
112
 
95
113
  EM.run do
114
+ Signal.trap("INT") { Quark::Server.quit() }
115
+ Signal.trap("TERM") { Quark::Server.quit() }
116
+
96
117
  if Quark::Config.get("debug")
97
118
  puts "Debug mode is ON"
98
119
  end
99
120
 
121
+ # socket
100
122
  if not @filename.nil? and File.writable?(File.dirname(@filename))
101
123
  puts "Starting socket server at #{@filename}..."
102
124
  EM::start_server(@filename, Quark::SocketServer)
103
125
  end
104
126
 
127
+ # UDP server
105
128
  if Quark::Config.get("quark.udp.enabled") === true
106
129
  @udp_address = Quark::Config.get("quark.udp.address", @address)
107
130
  @udp_port = Quark::Config.get("quark.udp.port", @port)
@@ -110,15 +133,33 @@ module Quark
110
133
  EM::open_datagram_socket(@udp_address, @udp_port, Quark::SocketServer)
111
134
  end
112
135
 
113
- if not @address.nil? and not @port.nil?
136
+ # TCP server
137
+ if Quark::Config.get("quark.tcp.enabled") === true
114
138
  puts "Starting TCP server on #{@address}:#{@port}..."
115
139
  EM::start_server(@address, @port, Quark::SocketServer)
116
140
  end
117
141
 
142
+ # HTTP server
143
+ if Quark::Config.get("quark.http.enabled") === true
144
+ @http_address = Quark::Config.get("quark.http.address", @address)
145
+ @http_port = Quark::Config.get("quark.http.port", 12180)
146
+
147
+ puts "Starting HTTP server on #{@http_address}:#{@http_port}..."
148
+ Quark::Server::HttpServer.new({
149
+ :address => @http_address,
150
+ :port => @http_port
151
+ }).run()
152
+ end
153
+
118
154
  if Quark::Config.get("quark.graphite_compat")
119
155
  puts "Graphite compatibility mode enabled: all sockets will accept Graphite-formatted metrics as observations"
120
156
  end
121
157
  end
122
158
  end
159
+
160
+ def self.quit()
161
+ puts "Stopping Quark..."
162
+ EM.stop()
163
+ end
123
164
  end
124
165
  end
@@ -1,6 +1,6 @@
1
1
  module Quark
2
2
  module SocketServer
3
- def process_command_fetch(data)
3
+ def self.process_command_fetch(data)
4
4
  raise Quark::ArgumentError.new("FETCH command requires at least 1 argument") if data.nil? or data.empty?
5
5
 
6
6
  rv = {}
@@ -1,6 +1,6 @@
1
1
  module Quark
2
2
  module SocketServer
3
- def process_command_observe(data)
3
+ def self.process_command_observe(data)
4
4
  id, value, timestamp = data.chomp.split(' ')
5
5
  timestamp = timestamp.to_i
6
6
 
@@ -2,7 +2,7 @@ module Quark
2
2
  module SocketServer
3
3
  require 'socket'
4
4
 
5
- def process_command_ping(data)
5
+ def self.process_command_ping(data)
6
6
  return {
7
7
  :alive => true,
8
8
  :hostname => Socket.gethostname(),
@@ -0,0 +1,70 @@
1
+ module Quark
2
+ class Server
3
+ class HttpServer
4
+ require 'sinatra'
5
+ require 'sinatra/cross_origin'
6
+ require 'thin'
7
+
8
+ class Base < Sinatra::Base
9
+ configure do
10
+ mime_type :json, 'application/json'
11
+
12
+ if Quark::Config.get("quark.http.cors") === true
13
+ set :allow_origin, :any
14
+ set :allow_methods, [:get, :post, :options]
15
+ set :allow_credentials, true
16
+ enable :cross_origin
17
+ end
18
+ end
19
+
20
+ before do
21
+ if Quark::Config.get("quark.http.cors") === true
22
+ headers 'Access-Control-Allow-Headers' => 'origin, x-requested-with, accept'
23
+ end
24
+
25
+ content_type :json
26
+ end
27
+
28
+ get '/?' do
29
+ MultiJson.dump({
30
+ :status => :ok,
31
+ :config => Quark::Config.all()
32
+ })
33
+ end
34
+
35
+ get '/call/:command/?*' do
36
+ MultiJson.dump(Quark::SocketServer.process_command("#{params[:command].upcase} #{params[:splat].first.gsub('/',' ')}".strip))
37
+ end
38
+
39
+ def _quark_command(command, payload)
40
+ io = nil
41
+
42
+ case settings.quark_protocol
43
+ when :tcp
44
+ io = TCPSocket.new(settings.quark_host, settings.quark_port)
45
+ io.puts("#{command.upcase} #{payload}".strip)
46
+ rv = io.gets()
47
+ when :socket
48
+ io = Socket.new(settings.quark_socket)
49
+ io.puts("#{command.upcase} #{payload}".strip)
50
+ rv = io.gets()
51
+ end
52
+
53
+ return MultiJson.load(rv)
54
+ end
55
+ end
56
+
57
+ def initialize(options=nil)
58
+ @_options = options || Quark::Config.get("quark.http",{})
59
+ end
60
+
61
+ def run()
62
+ Thin::Logging.silent = true unless Quark::Config.get("debug")
63
+ Thin::Server.start(@_options.get(:address,'127.0.0.1'), @_options.get(:port, 12180).to_i, Base.new(), {
64
+ :signals => false,
65
+ :threaded => true,
66
+ })
67
+ end
68
+ end
69
+ end
70
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2014-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
16
- requirement: &15249980 !ruby/object:Gem::Requirement
16
+ requirement: &5731120 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.7.9
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *15249980
24
+ version_requirements: *5731120
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: eventmachine
27
- requirement: &15249020 !ruby/object:Gem::Requirement
27
+ requirement: &5730020 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *15249020
35
+ version_requirements: *5730020
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: redis
38
- requirement: &15248140 !ruby/object:Gem::Requirement
38
+ requirement: &5728780 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 3.0.0
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *15248140
46
+ version_requirements: *5728780
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: hiredis
49
- requirement: &15263700 !ruby/object:Gem::Requirement
49
+ requirement: &5742700 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.5.2
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *15263700
57
+ version_requirements: *5742700
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: em-synchrony
60
- requirement: &15262720 !ruby/object:Gem::Requirement
60
+ requirement: &5739540 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.0.3
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *15262720
68
+ version_requirements: *5739540
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: hashlib
71
- requirement: &15261440 !ruby/object:Gem::Requirement
71
+ requirement: &5737440 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,40 @@ dependencies:
76
76
  version: 0.0.35
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *15261440
79
+ version_requirements: *5737440
80
+ - !ruby/object:Gem::Dependency
81
+ name: sinatra
82
+ requirement: &5359100 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *5359100
91
+ - !ruby/object:Gem::Dependency
92
+ name: sinatra-cross_origin
93
+ requirement: &5356080 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *5356080
102
+ - !ruby/object:Gem::Dependency
103
+ name: thin
104
+ requirement: &5352680 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: *5352680
80
113
  description: A small service for logging and retrieving timeseries metrics into a
81
114
  Redis server
82
115
  email: garyhetzel@gmail.com
@@ -86,6 +119,7 @@ extensions: []
86
119
  extra_rdoc_files: []
87
120
  files:
88
121
  - lib/quark.rb
122
+ - lib/quark/servers/http.rb
89
123
  - lib/quark/config.rb
90
124
  - lib/quark/commands/peek.rb
91
125
  - lib/quark/commands/fetch.rb