influxdb-api 0.0.1

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.
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'