influxdb 0.1.8 → 0.1.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 760707db17ad8199b2159d6e1e0f28e420f60f2f
4
- data.tar.gz: 1fb214ed28fe1978c7fc7a0b4a1aa9b2d6572988
3
+ metadata.gz: 79714dbe624e4485dfefc69e334b3234daf4c5c6
4
+ data.tar.gz: 8a36045de479f5406d65b332c191edb3cfe327bb
5
5
  SHA512:
6
- metadata.gz: 7348efe2e8cf889cfcb6f4fa5557eb217438abb7c87a43813b3da1290412107f7b73f0959cd7a590172ed0158ef9663716c3ac1de733dcb6e26038e90ddbacfd
7
- data.tar.gz: 4fbceddc8faa2e02bc7ef272c17c63d4fc81f73c9f964f51003cbd96769786d84d07369d52617737c5618f15a66fa67eaf55aaf9cbf76beb54ec8921a4373935
6
+ metadata.gz: f29ae07c03cd04314bfc82af8510334c7a6e829a33ef1eaa1a7d8a5be802bf53883bab852075d64b3fd142b319e7ea9ecfb5a4f447671bd5629af0be4087dda3
7
+ data.tar.gz: 478b0d0002b481bed502b6682f795bad4a61f69eaa4c459dacc9f8050023ba1ed78d15bd27187914d0c6b6d2ea0b6e6989945f5b399f97c0ffefb0596e2d9514
data/.gitignore CHANGED
@@ -12,6 +12,8 @@ test/tmp
12
12
  test/version_tmp
13
13
  tmp
14
14
  Gemfile.lock
15
+ .rvmrc
16
+ .ruby-version
15
17
 
16
18
  # YARD artifacts
17
19
  .yardoc
data/.travis.yml CHANGED
@@ -2,9 +2,9 @@ language: ruby
2
2
  before_install:
3
3
  - gem update bundler
4
4
  rvm:
5
- - 1.8.7-p374
6
- - ree
7
5
  - 1.9.3
8
6
  - 2.0.0
7
+ - 2.1.0
8
+ - 2.2.0
9
9
  - ruby-head
10
10
  - jruby
data/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  influxdb-ruby
2
2
  =============
3
3
 
4
+ # This library is not updated for InfluxDB 0.9.0. There are breaking changes to the API, use at your own risk.
5
+
6
+ We encourage you to submit a pull request if you have a contribution.
7
+
8
+ ----------
9
+
10
+
11
+
4
12
  [![Build Status](https://travis-ci.org/influxdb/influxdb-ruby.png?branch=master)](https://travis-ci.org/influxdb/influxdb-ruby)
5
13
 
6
14
  Ruby client library for [InfluxDB](http://influxdb.org/).
@@ -23,6 +31,8 @@ Connecting to a single host:
23
31
  require 'influxdb'
24
32
 
25
33
  influxdb = InfluxDB::Client.new host: "influxdb.domain.com"
34
+ # or
35
+ influxdb = InfluxDB::Client.new # no host given defaults connecting to localhost
26
36
  ```
27
37
 
28
38
  Connecting to multiple hosts (with built-in load balancing and failover):
@@ -40,6 +50,8 @@ require 'influxdb'
40
50
 
41
51
  influxdb = InfluxDB::Client.new
42
52
 
53
+ database = 'site_development'
54
+
43
55
  influxdb.create_database(database)
44
56
  ```
45
57
 
@@ -137,6 +149,25 @@ data = {
137
149
  influxdb.write_point(name, data, false, time_precision)
138
150
  ```
139
151
 
152
+ Write data via UDP:
153
+
154
+ ``` ruby
155
+ require 'influxdb'
156
+ host = '127.0.0.1'
157
+ port = 4444
158
+
159
+ influxdb = InfluxDB::Client.new :udp => { :host => host, :port => port }
160
+
161
+ name = 'hitchhiker'
162
+
163
+ data = {
164
+ :answer => 42,
165
+ :question => "life the universe and everything?"
166
+ }
167
+
168
+ influxdb.write_point(name, data)
169
+ ```
170
+
140
171
 
141
172
  List cluster admins:
142
173
 
data/influxdb.gemspec CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_runtime_dependency "json"
22
+ spec.add_runtime_dependency "cause"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.3"
24
25
  spec.add_development_dependency "rake"
25
- spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rspec", "~> 3.0.0"
26
27
  spec.add_development_dependency "webmock"
27
28
  end
data/lib/influxdb.rb CHANGED
@@ -5,4 +5,5 @@ require "influxdb/logger"
5
5
  require "influxdb/max_queue"
6
6
  require "influxdb/worker"
7
7
  require "influxdb/client"
8
+ require "influxdb/udp_client"
8
9
  require "influxdb/point_value"
@@ -3,6 +3,7 @@ require 'cgi'
3
3
  require 'net/http'
4
4
  require 'net/https'
5
5
  require 'json'
6
+ require 'cause'
6
7
 
7
8
  module InfluxDB
8
9
  class Client
@@ -12,10 +13,13 @@ module InfluxDB
12
13
  :password,
13
14
  :database,
14
15
  :time_precision,
16
+ :auth_method,
15
17
  :use_ssl,
18
+ :verify_ssl,
19
+ :ssl_ca_cert,
16
20
  :stopped
17
21
 
18
- attr_accessor :queue, :worker
22
+ attr_accessor :queue, :worker, :udp_client
19
23
 
20
24
  include InfluxDB::Logging
21
25
 
@@ -33,21 +37,30 @@ module InfluxDB
33
37
  #
34
38
  # Influxdb::Client.new 'db', :username => 'username' # override username, use 'db' as the db name
35
39
  #
40
+ # Influxdb::Client.new 'db', :path => '/prefix' # use the specified path prefix when building the
41
+ # # url e.g.: /prefix/db/dbname...
42
+ #
36
43
  # === Valid options in hash
37
44
  #
38
45
  # +:host+:: the hostname to connect to
39
46
  # +:port+:: the port to connect to
40
47
  # +:username+:: the username to use when executing commands
41
48
  # +:password+:: the password associated with the username
42
- # +:use_ssl+:: use ssl to connect
49
+ # +:use_ssl+:: use ssl to connect?
50
+ # +:verify_ssl+:: verify ssl server certificate?
51
+ # +:ssl_ca_cert+:: ssl CA certificate, chainfile or CA path. The system CA path is automatically included.
43
52
  def initialize *args
44
53
  @database = args.first if args.first.is_a? String
45
54
  opts = args.last.is_a?(Hash) ? args.last : {}
46
55
  @hosts = Array(opts[:hosts] || opts[:host] || ["localhost"])
47
56
  @port = opts[:port] || 8086
57
+ @path = opts[:path] || ""
48
58
  @username = opts[:username] || "root"
49
59
  @password = opts[:password] || "root"
60
+ @auth_method = %w{params basic_auth}.include?(opts[:auth_method]) ? opts[:auth_method] : "params"
50
61
  @use_ssl = opts[:use_ssl] || false
62
+ @verify_ssl = opts.fetch(:verify_ssl, true)
63
+ @ssl_ca_cert = opts[:ssl_ca_cert] || false
51
64
  @time_precision = opts[:time_precision] || "s"
52
65
  @initial_delay = opts[:initial_delay] || 0.01
53
66
  @max_delay = opts[:max_delay] || 30
@@ -65,14 +78,18 @@ module InfluxDB
65
78
  end
66
79
 
67
80
  @worker = InfluxDB::Worker.new(self) if @async
81
+ self.udp_client = opts[:udp] ? InfluxDB::UDPClient.new(opts[:udp][:host], opts[:udp][:port]) : nil
82
+
83
+ at_exit { stop! } if @retry > 0
84
+ end
68
85
 
69
- at_exit { stop! }
86
+ def ping
87
+ get "/ping"
70
88
  end
71
89
 
72
90
  ## allow options, e.g. influxdb.create_database('foo', replicationFactor: 3)
73
91
  def create_database(name, options = {})
74
- url = full_url("/db")
75
- options[:name] = name
92
+ url = full_url("/cluster/database_configs/#{name}")
76
93
  data = JSON.generate(options)
77
94
  post(url, data)
78
95
  end
@@ -85,6 +102,10 @@ module InfluxDB
85
102
  get full_url("/db")
86
103
  end
87
104
 
105
+ def authenticate_cluster_admin
106
+ get(full_url('/cluster_admins/authenticate'), true)
107
+ end
108
+
88
109
  def create_cluster_admin(username, password)
89
110
  url = full_url("/cluster_admins")
90
111
  data = JSON.generate({:name => username, :password => password})
@@ -105,9 +126,13 @@ module InfluxDB
105
126
  get full_url("/cluster_admins")
106
127
  end
107
128
 
108
- def create_database_user(database, username, password)
129
+ def authenticate_database_user(database)
130
+ get(full_url("/db/#{database}/authenticate"), true)
131
+ end
132
+
133
+ def create_database_user(database, username, password, options={})
109
134
  url = full_url("/db/#{database}/users")
110
- data = JSON.generate({:name => username, :password => password})
135
+ data = JSON.generate({:name => username, :password => password}.merge(options))
111
136
  post(url, data)
112
137
  end
113
138
 
@@ -133,6 +158,7 @@ module InfluxDB
133
158
  update_database_user(database, username, :admin => admin)
134
159
  end
135
160
 
161
+ # NOTE: Only cluster admin can call this
136
162
  def continuous_queries(database)
137
163
  get full_url("/db/#{database}/continuous_queries")
138
164
  end
@@ -141,12 +167,126 @@ module InfluxDB
141
167
  get full_url("/cluster/shards")
142
168
  end
143
169
 
144
- def delete_shard(shard_id, server_ids, username, password)
170
+ def delete_shard(shard_id, server_ids)
145
171
  data = JSON.generate({"serverIds" => server_ids})
146
- delete full_url("/cluster/shards/#{shard_id}", :u => username, :p => password), data
172
+ delete full_url("/cluster/shards/#{shard_id}"), data
173
+ end
174
+
175
+ # EXAMPLE:
176
+ #
177
+ # db.create_continuous_query(
178
+ # "select mean(sys) as sys, mean(usr) as usr from cpu group by time(15m)",
179
+ # "cpu.15m",
180
+ # )
181
+ #
182
+ # NOTE: Only cluster admin can call this
183
+ def create_continuous_query(query, name)
184
+ query("#{query} into #{name}")
185
+ end
186
+
187
+ # NOTE: Only cluster admin can call this
188
+ def get_continuous_query_list
189
+ query("list continuous queries")
190
+ end
191
+
192
+ # NOTE: Only cluster admin can call this
193
+ def delete_continuous_query(id)
194
+ query("drop continuous query #{id}")
195
+ end
196
+
197
+ def get_shard_space_list
198
+ get full_url("/cluster/shard_spaces")
199
+ end
200
+
201
+ def get_shard_space(database_name, shard_space_name)
202
+ get_shard_space_list.find do |shard_space|
203
+ shard_space["database"] == database_name &&
204
+ shard_space["name"] == shard_space_name
205
+ end
206
+ end
207
+
208
+ def create_shard_space(database_name, options = {})
209
+ url = full_url("/cluster/shard_spaces/#{database_name}")
210
+ data = JSON.generate(default_shard_space_options.merge(options))
211
+
212
+ post(url, data)
213
+ end
214
+
215
+ def delete_shard_space(database_name, shard_space_name)
216
+ delete full_url("/cluster/shard_spaces/#{database_name}/#{shard_space_name}")
217
+ end
218
+
219
+ ## Get the shard space first, so the user doesn't have to specify the existing options
220
+ def update_shard_space(database_name, shard_space_name, options)
221
+ shard_space_options = get_shard_space(database_name, shard_space_name)
222
+ shard_space_options.delete("database")
223
+
224
+ url = full_url("/cluster/shard_spaces/#{database_name}/#{shard_space_name}")
225
+ data = JSON.generate(shard_space_options.merge(options))
226
+
227
+ post(url, data)
228
+ end
229
+
230
+ def default_shard_space_options
231
+ {
232
+ "name" => "default",
233
+ "regEx" => "/.*/",
234
+ "retentionPolicy" => "inf",
235
+ "shardDuration" => "7d",
236
+ "replicationFactor" => 1,
237
+ "split" => 1
238
+ }
239
+ end
240
+
241
+ def configure_database(database_name, options = {})
242
+ url = full_url("/cluster/database_configs/#{database_name}")
243
+ data = JSON.generate(default_database_configuration.merge(options))
244
+
245
+ post(url, data)
246
+ end
247
+
248
+ def default_database_configuration
249
+ {:spaces => [default_shard_space_options]}
147
250
  end
148
251
 
149
252
  def write_point(name, data, async=@async, time_precision=@time_precision)
253
+ write_points([{:name => name, :data => data}], async, time_precision)
254
+ end
255
+
256
+ # Example:
257
+ # db.write_points(
258
+ # [
259
+ # {
260
+ # name: 'first_name',
261
+ # data: {
262
+ # value: 'val1'
263
+ # }
264
+ # },
265
+ # {
266
+ # name: 'first_name',
267
+ # data: {
268
+ # value: 'val1'
269
+ # }
270
+ # }
271
+ # ]
272
+ # )
273
+ def write_points(name_data_hashes_array, async=@async, time_precision=@time_precision)
274
+
275
+ payloads = []
276
+ name_data_hashes_array.each do |attrs|
277
+ payloads << generate_payload(attrs[:name], attrs[:data])
278
+ end
279
+
280
+ if async
281
+ worker.push(payloads)
282
+ elsif udp_client
283
+ udp_client.send(payloads)
284
+ else
285
+ _write(payloads, time_precision)
286
+ end
287
+ end
288
+
289
+ def generate_payload(name, data)
150
290
  data = data.is_a?(Array) ? data : [data]
151
291
  columns = data.reduce(:merge).keys.sort {|a,b| a.to_s <=> b.to_s}
152
292
  payload = {:name => name, :points => [], :columns => columns}
@@ -157,11 +297,7 @@ module InfluxDB
157
297
  end
158
298
  end
159
299
 
160
- if async
161
- worker.push(payload)
162
- else
163
- _write([payload], time_precision)
164
- end
300
+ payload
165
301
  end
166
302
 
167
303
  def _write(payload, time_precision=@time_precision)
@@ -201,19 +337,31 @@ module InfluxDB
201
337
  private
202
338
 
203
339
  def full_url(path, params={})
204
- params[:u] = @username
205
- params[:p] = @password
340
+ unless basic_auth?
341
+ params[:u] = @username
342
+ params[:p] = @password
343
+ end
206
344
 
207
345
  query = params.map { |k, v| [CGI.escape(k.to_s), "=", CGI.escape(v.to_s)].join }.join("&")
208
346
 
209
- URI::Generic.build(:path => path, :query => query).to_s
347
+ URI::Generic.build(:path => "#{@path}#{path}", :query => query).to_s
210
348
  end
211
349
 
212
- def get(url)
350
+ def basic_auth?
351
+ @auth_method == 'basic_auth'
352
+ end
353
+
354
+ def get(url, return_response = false)
213
355
  connect_with_retry do |http|
214
- response = http.request(Net::HTTP::Get.new(url))
356
+ request = Net::HTTP::Get.new(url)
357
+ request.basic_auth @username, @password if basic_auth?
358
+ response = http.request(request)
215
359
  if response.kind_of? Net::HTTPSuccess
216
- return JSON.parse(response.body)
360
+ if return_response
361
+ return response
362
+ else
363
+ return JSON.parse(response.body)
364
+ end
217
365
  elsif response.kind_of? Net::HTTPUnauthorized
218
366
  raise InfluxDB::AuthenticationError.new response.body
219
367
  else
@@ -225,7 +373,9 @@ module InfluxDB
225
373
  def post(url, data)
226
374
  headers = {"Content-Type" => "application/json"}
227
375
  connect_with_retry do |http|
228
- response = http.request(Net::HTTP::Post.new(url, headers), data)
376
+ request = Net::HTTP::Post.new(url, headers)
377
+ request.basic_auth @username, @password if basic_auth?
378
+ response = http.request(request, data)
229
379
  if response.kind_of? Net::HTTPSuccess
230
380
  return response
231
381
  elsif response.kind_of? Net::HTTPUnauthorized
@@ -239,7 +389,9 @@ module InfluxDB
239
389
  def delete(url, data = nil)
240
390
  headers = {"Content-Type" => "application/json"}
241
391
  connect_with_retry do |http|
242
- response = http.request(Net::HTTP::Delete.new(url, headers), data)
392
+ request = Net::HTTP::Delete.new(url, headers)
393
+ request.basic_auth @username, @password if basic_auth?
394
+ response = http.request(request, data)
243
395
  if response.kind_of? Net::HTTPSuccess
244
396
  return response
245
397
  elsif response.kind_of? Net::HTTPUnauthorized
@@ -261,6 +413,21 @@ module InfluxDB
261
413
  http.open_timeout = @open_timeout
262
414
  http.read_timeout = @read_timeout
263
415
  http.use_ssl = @use_ssl
416
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @verify_ssl
417
+
418
+ if @use_ssl
419
+ store = OpenSSL::X509::Store.new
420
+ store.set_default_paths
421
+ if @ssl_ca_cert
422
+ if File.directory?(@ssl_ca_cert)
423
+ store.add_path(@ssl_ca_cert)
424
+ else
425
+ store.add_file(@ssl_ca_cert)
426
+ end
427
+ end
428
+ http.cert_store = store
429
+ end
430
+
264
431
  block.call(http)
265
432
 
266
433
  rescue Timeout::Error, *InfluxDB::NET_HTTP_EXCEPTIONS => e
@@ -272,7 +439,7 @@ module InfluxDB
272
439
  delay = [@max_delay, delay * 2].min
273
440
  retry
274
441
  else
275
- raise e, "Tried #{retry_count-1} times to reconnect but failed."
442
+ raise InfluxDB::ConnectionError, "Tried #{retry_count-1} times to reconnect but failed."
276
443
  end
277
444
  ensure
278
445
  http.finish if http.started?
@@ -9,12 +9,13 @@ module InfluxDB
9
9
  end
10
10
 
11
11
  def self.logger
12
- @logger ||= ::Logger.new(STDERR).tap {|logger| logger.level = Logger::INFO}
12
+ return @logger unless @logger.nil?
13
+ @logger = ::Logger.new(STDERR).tap {|logger| logger.level = Logger::INFO}
13
14
  end
14
15
 
15
16
  private
16
17
  def log(level, message)
17
- InfluxDB::Logging.logger.send(level.to_sym, PREFIX + message)
18
+ InfluxDB::Logging.logger.send(level.to_sym, PREFIX + message) if InfluxDB::Logging.logger
18
19
  end
19
20
  end
20
21
  end
@@ -0,0 +1,16 @@
1
+ require "json"
2
+
3
+ module InfluxDB
4
+ class UDPClient
5
+ attr_accessor :socket
6
+ def initialize(host, port)
7
+ self.socket = UDPSocket.new
8
+ self.socket.connect(host, port)
9
+ end
10
+
11
+ def send(payload)
12
+ socket.send(JSON.generate(payload), 0)
13
+ rescue
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module InfluxDB
2
- VERSION = "0.1.8"
2
+ VERSION = "0.1.9"
3
3
  end
@@ -17,6 +17,11 @@ module InfluxDB
17
17
  @queue = InfluxDB::MaxQueue.new
18
18
  @client = client
19
19
  spawn_threads!
20
+
21
+ at_exit do
22
+ log :debug, "Thread exiting, flushing queue."
23
+ check_background_queue until @queue.empty?
24
+ end
20
25
  end
21
26
 
22
27
  def current_threads
@@ -28,7 +33,11 @@ module InfluxDB
28
33
  end
29
34
 
30
35
  def push(payload)
31
- queue.push(payload)
36
+ if payload.is_a? Array
37
+ payload.each {|p| queue.push(p) }
38
+ else
39
+ queue.push(payload)
40
+ end
32
41
  end
33
42
 
34
43
  def spawn_threads!
@@ -38,11 +47,6 @@ module InfluxDB
38
47
  Thread.new do
39
48
  Thread.current[:influxdb] = self.object_id
40
49
 
41
- at_exit do
42
- log :debug, "Thread exiting, flushing queue."
43
- check_background_queue(thread_num) until @queue.empty?
44
- end
45
-
46
50
  while !client.stopped?
47
51
  self.check_background_queue(thread_num)
48
52
  sleep rand(SLEEP_INTERVAL)
@@ -22,6 +22,7 @@ describe InfluxDB::Client do
22
22
  @influxdb.password.should == "root"
23
23
  @influxdb.use_ssl.should be_falsey
24
24
  @influxdb.time_precision.should == "s"
25
+ @influxdb.auth_method.should == "params"
25
26
  end
26
27
  end
27
28
 
@@ -101,16 +102,70 @@ describe InfluxDB::Client do
101
102
  @influxdb.password.should == "root"
102
103
  end
103
104
  end
105
+
106
+ describe "with auth_method basic auth specified" do
107
+ it "should be initialized with basic auth enabled" do
108
+ @influxdb = InfluxDB::Client.new :auth_method => 'basic_auth'
109
+
110
+ @influxdb.should be_a(InfluxDB::Client)
111
+ @influxdb.auth_method.should == 'basic_auth'
112
+ @influxdb.username.should == "root"
113
+ @influxdb.password.should == "root"
114
+ end
115
+ end
116
+
117
+ describe "with udp specified" do
118
+ it "should initialize a udp client" do
119
+ @influxdb = InfluxDB::Client.new :udp => { :host => 'localhost', :port => 4444 }
120
+ expect(@influxdb.udp_client).to be_a(InfluxDB::UDPClient)
121
+ end
122
+
123
+ context "without udp specfied" do
124
+ it "does not initialize a udp client" do
125
+ @influxdb = InfluxDB::Client.new
126
+ expect(@influxdb.udp_client).to be_nil
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+
133
+ context "with basic auth enabled" do
134
+ let(:args) { { :auth_method => 'basic_auth' } }
135
+ it "should use basic authorization for get" do
136
+ stub_request(:get, "http://username:password@influxdb.test:9999/").to_return(:body => '[]')
137
+ @influxdb.send(:get , @influxdb.send(:full_url,'/')).should == []
138
+ end
139
+ it "should use basic authorization for post" do
140
+ stub_request(:post, "http://username:password@influxdb.test:9999/")
141
+ @influxdb.send(:post , @influxdb.send(:full_url,'/'), {}).should be_a(Net::HTTPOK)
142
+ end
143
+ it "should use basic authorization for delete" do
144
+ stub_request(:delete, "http://username:password@influxdb.test:9999/")
145
+ @influxdb.send(:delete , @influxdb.send(:full_url,'/')).should be_a(Net::HTTPOK)
146
+ end
147
+ end
148
+
149
+ describe "#ping" do
150
+ it "should return status ok" do
151
+ status_ok = {"status" => "ok"}
152
+ stub_request(:get, "http://influxdb.test:9999/ping"
153
+ ).to_return(:body => JSON.generate(status_ok), :status => 200)
154
+
155
+ @influxdb.ping.should == status_ok
156
+ end
104
157
  end
105
158
 
106
159
  describe "#create_database" do
107
160
  it "should POST to create a new database" do
108
- stub_request(:post, "http://influxdb.test:9999/db").with(
161
+ stub_request(
162
+ :post, 'http://influxdb.test:9999/cluster/database_configs/foo'
163
+ ).with(
109
164
  :query => {:u => "username", :p => "password"},
110
- :body => {:name => "foo"}
165
+ :body => {:spaces => []}
111
166
  )
112
167
 
113
- @influxdb.create_database("foo").should be_a(Net::HTTPOK)
168
+ @influxdb.create_database("foo", {:spaces => []}).should be_a(Net::HTTPOK)
114
169
  end
115
170
  end
116
171
 
@@ -135,6 +190,16 @@ describe InfluxDB::Client do
135
190
  end
136
191
  end
137
192
 
193
+ describe "#authenticate_cluster_admin" do
194
+ it "should GET to authenticate a cluster admin" do
195
+ stub_request(:get, "http://influxdb.test:9999/cluster_admins/authenticate").with(
196
+ :query => {:u => "username", :p => "password"}
197
+ )
198
+
199
+ @influxdb.authenticate_cluster_admin.should be_a(Net::HTTPOK)
200
+ end
201
+ end
202
+
138
203
  describe "#create_cluster_admin" do
139
204
  it "should POST to create a new cluster admin" do
140
205
  stub_request(:post, "http://influxdb.test:9999/cluster_admins").with(
@@ -178,6 +243,16 @@ describe InfluxDB::Client do
178
243
  end
179
244
  end
180
245
 
246
+ describe "#authenticate_database_user" do
247
+ it "should GET to authenticate a database database" do
248
+ stub_request(:get, "http://influxdb.test:9999/db/foo/authenticate").with(
249
+ :query => {:u => "username", :p => "password"}
250
+ ).to_return(:body => '', :status => 200)
251
+
252
+ @influxdb.authenticate_database_user("foo").should be_a(Net::HTTPOK)
253
+ end
254
+ end
255
+
181
256
  describe "#create_database_user" do
182
257
  it "should POST to create a new database user" do
183
258
  stub_request(:post, "http://influxdb.test:9999/db/foo/users").with(
@@ -187,6 +262,20 @@ describe InfluxDB::Client do
187
262
 
188
263
  @influxdb.create_database_user("foo", "useruser", "passpass").should be_a(Net::HTTPOK)
189
264
  end
265
+
266
+ it "should POST to create a new database user with permissions" do
267
+ stub_request(:post, "http://influxdb.test:9999/db/foo/users").with(
268
+ :query => {:u => "username", :p => "password"},
269
+ :body => {:name => "useruser", :password => "passpass", :readFrom => "/read*/", :writeTo => "/write*/"}
270
+ )
271
+
272
+ @influxdb.create_database_user(
273
+ "foo",
274
+ "useruser",
275
+ "passpass",
276
+ {:readFrom => "/read*/", :writeTo => "/write*/"}
277
+ ).should be_a(Net::HTTPOK)
278
+ end
190
279
  end
191
280
 
192
281
  describe "#update_database_user" do
@@ -261,7 +350,174 @@ describe InfluxDB::Client do
261
350
  :query => {:u => "username", :p => "password"}
262
351
  )
263
352
 
264
- @influxdb.delete_shard(shard_id, [1, 2], "username", "password").should be_a(Net::HTTPOK)
353
+ @influxdb.delete_shard(shard_id, [1, 2]).should be_a(Net::HTTPOK)
354
+ end
355
+ end
356
+
357
+ describe "#create_continuous_query" do
358
+ it "should GET to create a continuous query" do
359
+ stub_request(:get, "http://influxdb.test:9999/db/database/series").with(
360
+ :query => { :q => "select sys from cpu into sys", :u => "username", :p => "password", :time_precision => "s"}
361
+ ).to_return(:body => JSON.generate({}))
362
+
363
+ @influxdb.create_continuous_query("select sys from cpu", "sys").should == {}
364
+ end
365
+ end
366
+
367
+ describe "#get_continuous_query_list" do
368
+ it "should GET to get continuous query list" do
369
+ body = [{
370
+ "name"=>"continuous queries",
371
+ "columns"=>["time", "sequence_number", "id", "query"],
372
+ "points"=>[
373
+ [1399, 1, 1, "select sys from cpu into sys"]
374
+ ]
375
+ }]
376
+ expected = {
377
+ "continuous queries" => [
378
+ {
379
+ "time" => 1399,
380
+ "sequence_number" => 1,
381
+ "id" => 1,
382
+ "query" => "select sys from cpu into sys"
383
+ }
384
+ ]
385
+ }
386
+ stub_request(:get, "http://influxdb.test:9999/db/database/series").with(
387
+ :query => { :q => "list continuous queries", :u => "username", :p => "password", :time_precision => "s"}
388
+ ).to_return(:body => JSON.generate(body))
389
+
390
+ @influxdb.get_continuous_query_list.should == expected
391
+ end
392
+ end
393
+
394
+ describe "#delete_continuous_query" do
395
+ it "should GET to delete continuous query" do
396
+ id = 1
397
+ stub_request(:get, "http://influxdb.test:9999/db/database/series").with(
398
+ :query => { :q => "drop continuous query #{id}", :u => "username", :p => "password", :time_precision => "s"}
399
+ ).to_return(:body => JSON.generate({}))
400
+
401
+ @influxdb.delete_continuous_query(id).should == {}
402
+ end
403
+ end
404
+
405
+ describe "#get_shard_space_list" do
406
+ let(:url) { "http://influxdb.test:9999/cluster/shard_spaces" }
407
+ let(:request_params) { {:query => {:u => "username", :p => "password"}} }
408
+ let(:response) { {:body => JSON.generate(shard_spaces, :status => 200)} }
409
+ let(:shard_spaces) { [@influxdb.default_shard_space_options.merge(:database => "foo")] }
410
+
411
+ it 'should GET a list of shard spaces' do
412
+ request = stub_request(:get, url).with(request_params).to_return(response)
413
+
414
+ @influxdb.get_shard_space_list
415
+
416
+ expect(request).to have_been_requested
417
+ end
418
+ end
419
+
420
+ describe "#get_shard_space" do
421
+ let(:url) { "http://influxdb.test:9999/cluster/shard_spaces" }
422
+ let(:request_params) { {:query => {:u => "username", :p => "password"}} }
423
+ let(:response) { {:body => JSON.generate(shard_spaces, :status => 200)} }
424
+
425
+ describe "#get_shard_space_list returns a non-empty list" do
426
+ let(:shard_spaces) { [@influxdb.default_shard_space_options.merge("database" => "foo")] }
427
+
428
+ it "finds the indicated shard space" do
429
+ request = stub_request(:get, url).with(request_params).to_return(response)
430
+
431
+ expect(@influxdb.get_shard_space('foo', 'default')).to eq shard_spaces.first
432
+
433
+ expect(request).to have_been_requested
434
+ end
435
+ end
436
+
437
+ describe "#get_shard_space_list returns an empty list" do
438
+ let(:shard_spaces) { [] }
439
+
440
+ it "finds no shard space" do
441
+ request = stub_request(:get, url).with(request_params).to_return(response)
442
+
443
+ expect(@influxdb.get_shard_space('foo', 'default')).to eq nil
444
+
445
+ expect(request).to have_been_requested
446
+ end
447
+ end
448
+ end
449
+
450
+ describe "#create_shard_space" do
451
+ let(:url) { "http://influxdb.test:9999/cluster/shard_spaces/foo" }
452
+ let(:request_params) do
453
+ {
454
+ :query => {:u => "username", :p => "password"},
455
+ :body => @influxdb.default_shard_space_options
456
+ }
457
+ end
458
+
459
+ it 'should POST to create a shard space' do
460
+ request = stub_request(:post, url).with(request_params)
461
+
462
+ @influxdb.create_shard_space("foo", @influxdb.default_shard_space_options)
463
+
464
+ expect(request).to have_been_requested
465
+ end
466
+ end
467
+
468
+ describe "#delete_shard_space" do
469
+ let(:url) { "http://influxdb.test:9999/cluster/shard_spaces/foo/default" }
470
+ let(:request_params) { {:query => {:u => "username", :p => "password"}} }
471
+
472
+ it 'should DELETE to delete the shard space' do
473
+ request = stub_request(:delete, url).with(request_params)
474
+
475
+ @influxdb.delete_shard_space("foo", "default")
476
+
477
+ expect(request).to have_been_requested
478
+ end
479
+ end
480
+
481
+ describe "#update_shard_space" do
482
+ let(:get_url) { "http://influxdb.test:9999/cluster/shard_spaces" }
483
+ let(:get_request_params) { {:query => {:u => "username", :p => "password"}} }
484
+ let(:get_response) { {:body => JSON.generate(shard_spaces, :status => 200)} }
485
+ let(:shard_spaces) { [@influxdb.default_shard_space_options.merge("database" => "foo")] }
486
+
487
+ let(:post_url) { "http://influxdb.test:9999/cluster/shard_spaces/foo/default" }
488
+ let(:post_request_params) do
489
+ {
490
+ :query => {:u => "username", :p => "password"},
491
+ :body => @influxdb.default_shard_space_options.merge("shardDuration" => "30d")
492
+ }
493
+ end
494
+
495
+ it 'should GET the shard space and then POST to update the shard space' do
496
+ get_request = stub_request(:get, get_url).with(get_request_params).to_return(get_response)
497
+ post_request = stub_request(:post, post_url).with(post_request_params)
498
+
499
+ @influxdb.update_shard_space("foo", "default", {"shardDuration" => "30d"})
500
+
501
+ expect(get_request).to have_been_requested
502
+ expect(post_request).to have_been_requested
503
+ end
504
+ end
505
+
506
+ describe "#configure_database" do
507
+ let(:url) { "http://influxdb.test:9999/cluster/database_configs/foo" }
508
+ let(:request_params) do
509
+ {
510
+ :query => {:u => "username", :p => "password"},
511
+ :body => @influxdb.default_database_configuration
512
+ }
513
+ end
514
+
515
+ it "should POST to create a new database config" do
516
+ request = stub_request(:post, url).with(request_params)
517
+
518
+ @influxdb.configure_database("foo").should be_a(Net::HTTPOK)
519
+
520
+ expect(request).to have_been_requested
265
521
  end
266
522
  end
267
523
 
@@ -307,14 +563,18 @@ describe InfluxDB::Client do
307
563
  it "raises when stopped" do
308
564
  @influxdb.stop!
309
565
  @influxdb.should_not_receive :sleep
310
- expect { subject }.to raise_error(Timeout::Error)
566
+ expect { subject }.to raise_error(InfluxDB::ConnectionError) do |e|
567
+ expect(e.cause).to be_an_instance_of(Timeout::Error)
568
+ end
311
569
  end
312
570
 
313
571
  context "when retry is 0" do
314
572
  let(:args) { { :retry => 0 } }
315
573
  it "raise error directly" do
316
574
  @influxdb.should_not_receive :sleep
317
- expect { subject }.to raise_error(Timeout::Error)
575
+ expect { subject }.to raise_error(InfluxDB::ConnectionError) do |e|
576
+ expect(e.cause).to be_an_instance_of(Timeout::Error)
577
+ end
318
578
  end
319
579
  end
320
580
 
@@ -323,7 +583,9 @@ describe InfluxDB::Client do
323
583
 
324
584
  it "raise error after 'n' attemps" do
325
585
  @influxdb.should_receive(:sleep).exactly(3).times
326
- expect { subject }.to raise_error(Timeout::Error)
586
+ expect { subject }.to raise_error(InfluxDB::ConnectionError) do |e|
587
+ expect(e.cause).to be_an_instance_of(Timeout::Error)
588
+ end
327
589
  end
328
590
  end
329
591
 
@@ -471,21 +733,41 @@ describe InfluxDB::Client do
471
733
  it "should push to the worker with payload if client is async" do
472
734
  @influxdb = InfluxDB::Client.new "database", :host => "influxdb.test", :async => true
473
735
 
474
- data = {:name => "juan", :age => 87, :time => Time.now.to_i}
475
- @influxdb.stub_chain(:worker, :push).with(hash_including({:name => 'seriez'})).and_return(:ok)
736
+ time = Time.now.to_i
737
+ data = {:name => "juan", :age => 87, :time => time}
738
+ expected_data = [{:name => 'seriez', :points => [[87, 'juan', time]], :columns => [:age, :name, :time]}]
739
+ @influxdb.stub_chain(:worker, :push).with(expected_data).and_return(:ok)
476
740
  @influxdb.write_point("seriez", data).should eq(:ok)
477
741
  end
478
742
 
479
743
  it "should push to the worker with payload if write_point call is async" do
480
744
  @influxdb = InfluxDB::Client.new "database", :host => "influxdb.test", :async => false
481
745
 
482
- data = {:name => "juan", :age => 87, :time => Time.now.to_i}
483
- @influxdb.stub_chain(:worker, :push).with(hash_including({:name => 'seriez'})).and_return(:ok)
746
+ time = Time.now.to_i
747
+ data = {:name => "juan", :age => 87, :time => time}
748
+ expected_data = [{:name => 'seriez', :points => [[87, 'juan', time]], :columns => [:age, :name, :time]}]
749
+ @influxdb.stub_chain(:worker, :push).with(expected_data).and_return(:ok)
484
750
  @influxdb.write_point("seriez", data, true).should eq(:ok)
485
751
  end
486
752
 
487
753
  end
488
754
 
755
+ describe "udp" do
756
+ let(:udp_client) { double }
757
+ let(:time) { Time.now.to_i }
758
+ let(:influxdb) { InfluxDB::Client.new(:udp => { :host => "localhost", :port => 44444 }) }
759
+
760
+ before do
761
+ allow(InfluxDB::UDPClient).to receive(:new).with('localhost', 44444).and_return(udp_client)
762
+ end
763
+
764
+ it "should send payload via udp if udp client is set up" do
765
+ expect(udp_client).to receive(:send).with([{:name=>"seriez", :points=>[[87, "juan", time]], :columns=>[:age, :name, :time]}])
766
+ data = {:name => "juan", :age => 87, :time => time}
767
+ influxdb.write_point("seriez", data)
768
+ end
769
+ end
770
+
489
771
  end
490
772
 
491
773
  describe "#execute_queries" do
@@ -23,6 +23,22 @@ describe InfluxDB::Logging do
23
23
  InfluxDB::Logging.logger = new_logger
24
24
  expect(InfluxDB::Logging.logger).to eq(new_logger)
25
25
  end
26
+
27
+ it "allows disabling of a logger" do
28
+ InfluxDB::Logging.logger = false
29
+ expect(InfluxDB::Logging.logger).to eql false
30
+ end
31
+
32
+ context "when logging is disabled" do
33
+
34
+ subject { LoggerTest.new }
35
+
36
+ it "does not log" do
37
+ InfluxDB::Logging.logger = false
38
+ expect(InfluxDB::Logging.logger).not_to receive(:debug)
39
+ subject.write_to_log(:debug, 'test')
40
+ end
41
+ end
26
42
 
27
43
  context "when included in classes" do
28
44
 
@@ -0,0 +1,33 @@
1
+ require "spec_helper"
2
+ require "json"
3
+
4
+ describe InfluxDB::UDPClient do
5
+ subject { described_class.new("localhost", 44444) }
6
+ let(:message) { [{ "foo" => "bar" }] }
7
+
8
+ describe "#send" do
9
+ it "sends a UPD packet" do
10
+ s = UDPSocket.new
11
+ s.bind("localhost", 44444)
12
+ subject.send(message)
13
+ rec_mesage = JSON.parse(s.recvfrom(15).first)
14
+ expect(rec_mesage).to eq message
15
+ end
16
+
17
+ context "it can't connect" do
18
+ before do
19
+ subject.socket = FailingSocket.new
20
+ end
21
+
22
+ it "doesn't blow up" do
23
+ expect { subject.send(message) }.to_not raise_error
24
+ end
25
+ end
26
+
27
+ class FailingSocket < UDPSocket
28
+ def send(*args)
29
+ fail
30
+ end
31
+ end
32
+ end
33
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,11 @@
1
- require "influxdb"
2
- require "webmock/rspec"
1
+ require 'influxdb'
2
+ require 'webmock/rspec'
3
+
4
+ RSpec.configure do |config|
5
+ config.mock_with :rspec do |mocks|
6
+ mocks.syntax = [:should, :expect]
7
+ end
8
+ config.expect_with :rspec do |expectations|
9
+ expectations.syntax = [:should, :expect]
10
+ end
11
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: influxdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Todd Persen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-06 00:00:00.000000000 Z
11
+ date: 2015-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: cause
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,16 +70,16 @@ dependencies:
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - '>='
73
+ - - ~>
60
74
  - !ruby/object:Gem::Version
61
- version: '0'
75
+ version: 3.0.0
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - '>='
80
+ - - ~>
67
81
  - !ruby/object:Gem::Version
68
- version: '0'
82
+ version: 3.0.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: webmock
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,11 +114,13 @@ files:
100
114
  - lib/influxdb/logger.rb
101
115
  - lib/influxdb/max_queue.rb
102
116
  - lib/influxdb/point_value.rb
117
+ - lib/influxdb/udp_client.rb
103
118
  - lib/influxdb/version.rb
104
119
  - lib/influxdb/worker.rb
105
120
  - spec/influxdb/client_spec.rb
106
121
  - spec/influxdb/logger_spec.rb
107
122
  - spec/influxdb/point_value_spec.rb
123
+ - spec/influxdb/udp_client_spec.rb
108
124
  - spec/influxdb/worker_spec.rb
109
125
  - spec/influxdb_spec.rb
110
126
  - spec/max_queue_spec.rb
@@ -129,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
145
  version: '0'
130
146
  requirements: []
131
147
  rubyforge_project:
132
- rubygems_version: 2.1.11
148
+ rubygems_version: 2.0.14
133
149
  signing_key:
134
150
  specification_version: 4
135
151
  summary: Ruby library for InfluxDB.
@@ -137,6 +153,7 @@ test_files:
137
153
  - spec/influxdb/client_spec.rb
138
154
  - spec/influxdb/logger_spec.rb
139
155
  - spec/influxdb/point_value_spec.rb
156
+ - spec/influxdb/udp_client_spec.rb
140
157
  - spec/influxdb/worker_spec.rb
141
158
  - spec/influxdb_spec.rb
142
159
  - spec/max_queue_spec.rb