influxdb-api 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +208 -0
- data/Rakefile +6 -0
- data/influxdb-api.gemspec +27 -0
- data/lib/influxdb-api.rb +2 -0
- data/lib/influxdb.rb +4 -0
- data/lib/influxdb/api.rb +38 -0
- data/lib/influxdb/api/client.rb +99 -0
- data/lib/influxdb/api/client/connection.rb +55 -0
- data/lib/influxdb/api/client/connection_pool.rb +52 -0
- data/lib/influxdb/api/client/errors.rb +62 -0
- data/lib/influxdb/api/client/response.rb +14 -0
- data/lib/influxdb/api/client/selector.rb +27 -0
- data/lib/influxdb/api/configuration.rb +116 -0
- data/lib/influxdb/api/database.rb +29 -0
- data/lib/influxdb/api/extensions.rb +15 -0
- data/lib/influxdb/api/namespaces.rb +50 -0
- data/lib/influxdb/api/namespaces/base.rb +61 -0
- data/lib/influxdb/api/namespaces/cluster_admins.rb +14 -0
- data/lib/influxdb/api/namespaces/continuous_queries.rb +13 -0
- data/lib/influxdb/api/namespaces/databases.rb +13 -0
- data/lib/influxdb/api/namespaces/series.rb +52 -0
- data/lib/influxdb/api/namespaces/servers.rb +12 -0
- data/lib/influxdb/api/namespaces/shard_spaces.rb +33 -0
- data/lib/influxdb/api/namespaces/shards.rb +10 -0
- data/lib/influxdb/api/namespaces/users.rb +18 -0
- data/lib/influxdb/api/namespaces/with_database.rb +20 -0
- data/lib/influxdb/api/server_version.rb +62 -0
- data/lib/influxdb/api/version.rb +5 -0
- data/spec/lib/influxdb/api/client/connection_pool_spec.rb +61 -0
- data/spec/lib/influxdb/api/client/connection_spec.rb +72 -0
- data/spec/lib/influxdb/api/client/response_spec.rb +11 -0
- data/spec/lib/influxdb/api/client/selector_spec.rb +24 -0
- data/spec/lib/influxdb/api/client_spec.rb +110 -0
- data/spec/lib/influxdb/api/configuration_spec.rb +54 -0
- data/spec/lib/influxdb/api/database_spec.rb +32 -0
- data/spec/lib/influxdb/api/namespaces/cluster_admins_spec.rb +46 -0
- data/spec/lib/influxdb/api/namespaces/continuous_queries_spec.rb +42 -0
- data/spec/lib/influxdb/api/namespaces/databases_spec.rb +36 -0
- data/spec/lib/influxdb/api/namespaces/series_spec.rb +119 -0
- data/spec/lib/influxdb/api/namespaces/servers_spec.rb +30 -0
- data/spec/lib/influxdb/api/namespaces/shard_spaces_spec.rb +55 -0
- data/spec/lib/influxdb/api/namespaces/shards_spec.rb +52 -0
- data/spec/lib/influxdb/api/namespaces/users_spec.rb +55 -0
- data/spec/lib/influxdb/api/namespaces_spec.rb +65 -0
- data/spec/lib/influxdb/api/server_version_spec.rb +51 -0
- data/spec/spec_helper.rb +28 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|
data/lib/influxdb-api.rb
ADDED
data/lib/influxdb.rb
ADDED
data/lib/influxdb/api.rb
ADDED
@@ -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'
|