influxdb-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +12 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +208 -0
  8. data/Rakefile +6 -0
  9. data/influxdb-api.gemspec +27 -0
  10. data/lib/influxdb-api.rb +2 -0
  11. data/lib/influxdb.rb +4 -0
  12. data/lib/influxdb/api.rb +38 -0
  13. data/lib/influxdb/api/client.rb +99 -0
  14. data/lib/influxdb/api/client/connection.rb +55 -0
  15. data/lib/influxdb/api/client/connection_pool.rb +52 -0
  16. data/lib/influxdb/api/client/errors.rb +62 -0
  17. data/lib/influxdb/api/client/response.rb +14 -0
  18. data/lib/influxdb/api/client/selector.rb +27 -0
  19. data/lib/influxdb/api/configuration.rb +116 -0
  20. data/lib/influxdb/api/database.rb +29 -0
  21. data/lib/influxdb/api/extensions.rb +15 -0
  22. data/lib/influxdb/api/namespaces.rb +50 -0
  23. data/lib/influxdb/api/namespaces/base.rb +61 -0
  24. data/lib/influxdb/api/namespaces/cluster_admins.rb +14 -0
  25. data/lib/influxdb/api/namespaces/continuous_queries.rb +13 -0
  26. data/lib/influxdb/api/namespaces/databases.rb +13 -0
  27. data/lib/influxdb/api/namespaces/series.rb +52 -0
  28. data/lib/influxdb/api/namespaces/servers.rb +12 -0
  29. data/lib/influxdb/api/namespaces/shard_spaces.rb +33 -0
  30. data/lib/influxdb/api/namespaces/shards.rb +10 -0
  31. data/lib/influxdb/api/namespaces/users.rb +18 -0
  32. data/lib/influxdb/api/namespaces/with_database.rb +20 -0
  33. data/lib/influxdb/api/server_version.rb +62 -0
  34. data/lib/influxdb/api/version.rb +5 -0
  35. data/spec/lib/influxdb/api/client/connection_pool_spec.rb +61 -0
  36. data/spec/lib/influxdb/api/client/connection_spec.rb +72 -0
  37. data/spec/lib/influxdb/api/client/response_spec.rb +11 -0
  38. data/spec/lib/influxdb/api/client/selector_spec.rb +24 -0
  39. data/spec/lib/influxdb/api/client_spec.rb +110 -0
  40. data/spec/lib/influxdb/api/configuration_spec.rb +54 -0
  41. data/spec/lib/influxdb/api/database_spec.rb +32 -0
  42. data/spec/lib/influxdb/api/namespaces/cluster_admins_spec.rb +46 -0
  43. data/spec/lib/influxdb/api/namespaces/continuous_queries_spec.rb +42 -0
  44. data/spec/lib/influxdb/api/namespaces/databases_spec.rb +36 -0
  45. data/spec/lib/influxdb/api/namespaces/series_spec.rb +119 -0
  46. data/spec/lib/influxdb/api/namespaces/servers_spec.rb +30 -0
  47. data/spec/lib/influxdb/api/namespaces/shard_spaces_spec.rb +55 -0
  48. data/spec/lib/influxdb/api/namespaces/shards_spec.rb +52 -0
  49. data/spec/lib/influxdb/api/namespaces/users_spec.rb +55 -0
  50. data/spec/lib/influxdb/api/namespaces_spec.rb +65 -0
  51. data/spec/lib/influxdb/api/server_version_spec.rb +51 -0
  52. data/spec/spec_helper.rb +28 -0
  53. metadata +183 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0e2208d19896cd4f3845daad7257e5532ca4cfd
4
+ data.tar.gz: 7d22c8d5097873862de14b516777add3d7492da8
5
+ SHA512:
6
+ metadata.gz: c34a6269df801cff5bf9b337584b4f7f70a83f6547e468f233679da6a84e479a854be9eb4eec06579ab822ce1501b2c6c52933e4ab4de2cf4539f04f0a0f0ec8
7
+ data.tar.gz: b488bff8326ac3902939e39826a45c4f4e469ec121769b937966ddf5811266068d379a7fd66d2d687f763ef301ca27be70e5e332ed7bf87d4e1daed485e156df
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --backtrace
3
+ --order random
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.1
6
+ - rbx-2
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in influxdb-api.gemspec
4
+ gemspec
5
+
6
+ gem 'oj'
7
+ gem 'pry'
8
+
9
+ group :test do
10
+ gem 'timecop'
11
+ gem 'webmock', require: 'webmock/rspec'
12
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 undr
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,208 @@
1
+ # Ruby client for InfluxDB
2
+
3
+ [![Build Status](https://travis-ci.org/undr/influxdb-api.svg?branch=master)](https://travis-ci.org/undr/influxdb-api) [![Code Climate](https://codeclimate.com/github/undr/influxdb-api/badges/gpa.svg)](https://codeclimate.com/github/undr/influxdb-api)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'influxdb-api'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ $ gem install influxdb-api
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### Client configuration
28
+
29
+ There are two ways to obtain a fully-configured client:
30
+
31
+ - Get default client with default configuration, or
32
+ - Create client with custom configuration.
33
+
34
+ To configure default client you should pass a block to the method `Influxdb::Api.configure`.
35
+
36
+ ```ruby
37
+ Influxdb::Api.configure do |c|
38
+ # Credentials
39
+ c.user = 'root'
40
+ c.password = 'root'
41
+
42
+ # Servers pool
43
+ c.hosts = [
44
+ { host: 'influx01.server.com', port: 8086 },
45
+ 'influx02.server.com',
46
+ URI.parse('http://influx03.server.com:8086')
47
+ ]
48
+
49
+ # By default it does not try to send request again if request failed.
50
+ # You can change it by specifying number of trying.
51
+ c.retry_on_failure = 3
52
+
53
+ # Faraday connection options
54
+ c.connection_options = {}
55
+
56
+ # Faraday connection block
57
+ c.connection_block do |conn|
58
+ conn.adapter :typhoeus
59
+ end
60
+
61
+ # Turn on or turn off logging
62
+ c.log = true
63
+ # or
64
+ c.logger = Logger.new('./log/influxdb-api.log')
65
+
66
+ # Custom serializer. It should respond to methods #load and #dump
67
+ # Default: MultiJson
68
+ c.serializer = CustomJsonSerializer.new
69
+
70
+ # Connection selector.
71
+ # Default: Influxdb::Api::Client::Selector::RoundRobin
72
+ c.selector = Influxdb::Api::Client::Selector::Random.new
73
+ end
74
+
75
+ client = Influxdb::Api.client
76
+
77
+ client.config.user
78
+ # => "root"
79
+ client.config.retry_on_failure
80
+ # => 3
81
+ ```
82
+
83
+ Also, you can create client with custom configuration. Configuration will be inherited from default configuration and all needed options will be overridden.
84
+
85
+ ```ruby
86
+ client = Influxdb::Api.new do |c|
87
+ c.user = 'dbuser'
88
+ c.password = 'dbpassword'
89
+ end
90
+
91
+ client.config.user
92
+ # => "dbuser"
93
+ client.config.retry_on_failure
94
+ # => 3
95
+ ```
96
+
97
+ ### Available methods
98
+
99
+ ```ruby
100
+ client = Influxdb::Api.client
101
+
102
+ client.databases.all
103
+ # => [{"name"=>"dbname"}]
104
+ client.databases.create('dbname')
105
+ # => true
106
+ client.databases.delete('dbname')
107
+ # => true
108
+
109
+ database = client.databases('dbname')
110
+
111
+ database.series.all
112
+ # => ["cpu"]
113
+ database.series.execute('select * from /.*/')
114
+ # => {"cpu"=>[{"time"=>1411173197058, "sequence_number"=>200001, "value"=>13.5}]}
115
+ database.series.raw_execute('select * from /.*/')
116
+ # => [{"name"=>"cpu", "columns"=>["time", "sequence_number", "value"], "points"=>[[1411173197058, 200001, 13.5]]}]
117
+ database.series.write(:cpu, value: 13.5)
118
+ # => true
119
+ database.series.write(:cpu, [{ value: 13.5 }, { value: 10.0 }])
120
+ # => true
121
+ database.series.write(cpu: { value: 43.9 }, memory: { value: 2500853760 })
122
+ # => true
123
+ database.series.delete('seriesname')
124
+ # => true
125
+
126
+ database.users.all
127
+ # => [{"name"=>"username", "isAdmin"=>true}]
128
+ database.users.find('username')
129
+ # => {"name"=>"username", "isAdmin"=>true}
130
+ database.users.create(name: 'username', password: 'mypass', isAdmin: true)
131
+ # => true
132
+ database.users.update('username', admin: false)
133
+ # => true
134
+ database.users.delete('username')
135
+ # => true
136
+
137
+ database.continuous_queries.all
138
+ # => [{"id"=>1, "query"=>"select MEAN(user) as user_mean from cpu group by time(1m) into cpu.1m.user_mean"}]
139
+ database.continuous_queries.create('select MEAN(user) as user_mean from cpu group by time(1m) into cpu.1m.user_mean')
140
+ # => true
141
+ database.continuous_queries.delete(1)
142
+ # => true
143
+
144
+ # I haven't tested these methods yet. They aren't implemented on my influxdb server.
145
+ database.shard_spaces.all
146
+ database.shard_spaces.create(attrs)
147
+ database.shard_spaces.update('spacename', attrs)
148
+ database.shard_spaces.delete('spacename')
149
+
150
+ client.cluster_admins.all
151
+ # => [{"name"=>"root"}]
152
+ client.cluster_admins.create(name: 'username', password: 'pass')
153
+ # => true
154
+ client.cluster_admins.update('username', password: 'newpass')
155
+ # => true
156
+ client.cluster_admins.delete('username')
157
+ # => true
158
+
159
+ client.servers.all
160
+ # => [{"id"=>1, "protobufConnectString"=>"undr.local:8099"}]
161
+ client.servers.delete(1)
162
+ # => true
163
+
164
+ client.shards.all
165
+ # => {"longTerm"=>[],
166
+ # "shortTerm"=>
167
+ # [{"endTime"=>1411603200, "id"=>2, "serverIds"=>[1], "startTime"=>1410998400}, {"endTime"=>1410998400, "id"=>1, "serverIds"=>[1], "startTime"=>1410393600}]}
168
+
169
+ client.shards.create(attrs)
170
+ # => true
171
+ client.shards.delete(1)
172
+ # => true
173
+
174
+ v = client.version
175
+ # => "InfluxDB v0.7.3 (git: 216a3eb) (leveldb: 1.15)"
176
+ v > '0.7.6'
177
+ # => false
178
+ v > '0.7'
179
+ # => true
180
+ v.major
181
+ # => 0
182
+ v.minor
183
+ # => 7
184
+ v.patch
185
+ # => 3
186
+ v.git
187
+ # => "216a3eb"
188
+ v.engine
189
+ # "leveldb: 1.15.0"
190
+ v.engine.major
191
+ # => 1
192
+ v.engine.minor
193
+ # => 15
194
+ v.engine.patch
195
+ # => 0
196
+ client.sync?
197
+ # => true
198
+ client.interfaces
199
+ # => ["default"]
200
+ ```
201
+
202
+ ## Contributing
203
+
204
+ 1. Fork it
205
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
206
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
207
+ 4. Push to the branch (`git push origin my-new-feature`)
208
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'influxdb/api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "influxdb-api"
8
+ spec.version = Influxdb::Api::VERSION
9
+ spec.authors = ["undr"]
10
+ spec.email = ["undr@yandex.ru"]
11
+ spec.description = %q{Ruby client for InfluxDB }
12
+ spec.summary = %q{Ruby client for InfluxDB }
13
+ spec.homepage = "https://github.com/undr/influxdb-api"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "faraday"
22
+ spec.add_dependency "multi_json"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ end
@@ -0,0 +1,2 @@
1
+ require "influxdb"
2
+
@@ -0,0 +1,4 @@
1
+ require "influxdb/api"
2
+
3
+ module Influxdb
4
+ end
@@ -0,0 +1,38 @@
1
+ require 'multi_json'
2
+ require 'faraday'
3
+ require 'ostruct'
4
+
5
+ require_relative 'api/version'
6
+ require_relative 'api/extensions'
7
+ require_relative 'api/namespaces'
8
+ require_relative 'api/database'
9
+ require_relative 'api/server_version'
10
+
11
+ require_relative 'api/configuration'
12
+ require_relative 'api/client'
13
+
14
+ module Influxdb
15
+ module Api
16
+ extend self
17
+
18
+ attr_writer :client, :config
19
+
20
+ def new
21
+ instance_config = config.dup
22
+ yield instance_config if block_given?
23
+ Client.new(instance_config)
24
+ end
25
+
26
+ def client
27
+ @client ||= Client.new
28
+ end
29
+
30
+ def config
31
+ @config ||= Configuration.new
32
+ end
33
+
34
+ def configure
35
+ yield config
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,99 @@
1
+ module Influxdb
2
+ module Api
3
+ class Client
4
+ include Namespaces
5
+
6
+ attr_reader :config
7
+
8
+ def initialize(config = Influxdb::Api.config)
9
+ @config = config
10
+ @connection_pool = ConnectionPool.new(config)
11
+ @last_request_at = Time.now
12
+ @resurrect_after = 60
13
+ end
14
+
15
+ def perform_request(method, path, params = {}, body = nil, &block)
16
+ method = method.downcase.to_sym unless method.is_a?(Symbol)
17
+
18
+ response = with_retry(path, params) do |connection, url|
19
+ connection.basic_auth(config.user, config.password)
20
+ headers = { 'Content-Type' => 'application/json' }
21
+
22
+ connection.run_request(method, url, (body ? convert_to_json(body) : nil), headers, &block)
23
+ end
24
+
25
+ raise_transport_error(response) if response.status.to_i >= 300
26
+
27
+ json = config.serializer.load(response.body) if response.headers && response.headers["content-type"] =~ /json/
28
+
29
+ Response.new(response.status, json || response.body, response.headers)
30
+ ensure
31
+ @last_request_at = Time.now
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :connection_pool, :last_request_at, :resurrect_after
37
+
38
+ def with_retry(path, params, &block)
39
+ tries = 0
40
+
41
+ begin
42
+ tries += 1
43
+ connection = get_connection or raise Error.new("Cannot get new connection from pool.")
44
+
45
+ response = block.call(connection.connection, connection.full_path(path, params))
46
+
47
+ connection.healthy! if connection.failures > 0
48
+ Response.new(response.status, response.body, response.headers)
49
+ rescue ::Faraday::Error::ConnectionFailed, ::Faraday::Error::TimeoutError => e
50
+ logger.error "[#{e.class}] #{e.message} #{connection.host.inspect}" if logger
51
+
52
+ connection.dead!
53
+
54
+ raise e unless config.retry_on_failure
55
+
56
+ logger.warn "[#{e.class}] Attempt #{tries} connecting to #{connection.host.inspect}" if logger
57
+
58
+ retry if tries < config.retry_on_failure.to_i
59
+
60
+ logger.fatal "[#{e.class}] Cannot connect to #{connection.host.inspect} after #{tries} tries" if logger
61
+ raise e
62
+ rescue Exception => e
63
+ host = connection.host if connection
64
+ logger.fatal "[#{e.class}] #{e.message} (#{host.inspect})" if logger
65
+ raise e
66
+ end
67
+ end
68
+
69
+ def raise_transport_error(response)
70
+ logger.fatal "[#{response.status}] #{response.body}" if logger
71
+ error = ERRORS[response.status] || ServerError
72
+ raise error.new "[#{response.status}] #{response.body}"
73
+ end
74
+
75
+ def resurrect_dead_connections!
76
+ connection_pool.dead.each{|c| c.resurrect! }
77
+ end
78
+
79
+ def get_connection
80
+ resurrect_dead_connections! if Time.now > last_request_at + resurrect_after
81
+ connection_pool.get_connection
82
+ end
83
+
84
+ def convert_to_json(body, options = {})
85
+ body.is_a?(String) ? body : config.serializer.dump(body, options)
86
+ end
87
+
88
+ def logger
89
+ config.logger
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ require_relative 'client/response'
96
+ require_relative 'client/selector'
97
+ require_relative 'client/connection'
98
+ require_relative 'client/connection_pool'
99
+ require_relative 'client/errors'