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
@@ -0,0 +1,55 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Client
|
4
|
+
class Connection
|
5
|
+
attr_reader :host, :connection, :failures, :dead_since, :config
|
6
|
+
|
7
|
+
def initialize(host, connection, config = Influxdb::Api.config)
|
8
|
+
@config = config
|
9
|
+
@host = host
|
10
|
+
@connection = connection
|
11
|
+
@failures = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def full_path(path, params={})
|
15
|
+
path + (params.empty? ? '' : "?#{::Faraday::Utils::ParamsHash[params].to_query}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def dead?
|
19
|
+
!!@dead
|
20
|
+
end
|
21
|
+
|
22
|
+
def dead!
|
23
|
+
@dead = true
|
24
|
+
@failures += 1
|
25
|
+
@dead_since = Time.now
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def alive!
|
30
|
+
@dead = false
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def healthy!
|
35
|
+
@dead = false
|
36
|
+
@failures = 0
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def resurrect!
|
41
|
+
alive! if resurrectable?
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def resurrectable?
|
46
|
+
Time.now > dead_since + (config.resurrect_timeout * 2 ** (failures - 1))
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
"<#{self.class.name} host: #{host} (#{dead? ? 'dead since ' + dead_since.to_s : 'alive'})>"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Client
|
4
|
+
class ConnectionPool
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
def initialize(config = Influxdb::Api.config)
|
8
|
+
@config = config
|
9
|
+
@connections = build_connections
|
10
|
+
end
|
11
|
+
|
12
|
+
def connections
|
13
|
+
@connections.reject{|c| c.dead? }
|
14
|
+
end
|
15
|
+
alias :alive :connections
|
16
|
+
|
17
|
+
def dead
|
18
|
+
@connections.select{|c| c.dead? }
|
19
|
+
end
|
20
|
+
|
21
|
+
def all
|
22
|
+
@connections
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&block)
|
26
|
+
connections.each(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_connection
|
30
|
+
if connections.empty? && dead_connection = dead.sort{|a, b| a.failures <=> b.failures }.first
|
31
|
+
dead_connection.alive!
|
32
|
+
end
|
33
|
+
config.selector.select_from(alive)
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_connections
|
37
|
+
config.hosts.map do |host|
|
38
|
+
Connection.new(
|
39
|
+
host,
|
40
|
+
::Faraday::Connection.new(
|
41
|
+
host,
|
42
|
+
config.connection_options,
|
43
|
+
&config.connection_block
|
44
|
+
),
|
45
|
+
config
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Client
|
4
|
+
class Error < StandardError; end
|
5
|
+
class ServerError < StandardError; end
|
6
|
+
|
7
|
+
module Errors; end
|
8
|
+
|
9
|
+
HTTP_STATUSES = {
|
10
|
+
300 => 'MultipleChoices',
|
11
|
+
301 => 'MovedPermanently',
|
12
|
+
302 => 'Found',
|
13
|
+
303 => 'SeeOther',
|
14
|
+
304 => 'NotModified',
|
15
|
+
305 => 'UseProxy',
|
16
|
+
307 => 'TemporaryRedirect',
|
17
|
+
308 => 'PermanentRedirect',
|
18
|
+
|
19
|
+
400 => 'BadRequest',
|
20
|
+
401 => 'Unauthorized',
|
21
|
+
402 => 'PaymentRequired',
|
22
|
+
403 => 'Forbidden',
|
23
|
+
404 => 'NotFound',
|
24
|
+
405 => 'MethodNotAllowed',
|
25
|
+
406 => 'NotAcceptable',
|
26
|
+
407 => 'ProxyAuthenticationRequired',
|
27
|
+
408 => 'RequestTimeout',
|
28
|
+
409 => 'Conflict',
|
29
|
+
410 => 'Gone',
|
30
|
+
411 => 'LengthRequired',
|
31
|
+
412 => 'PreconditionFailed',
|
32
|
+
413 => 'RequestEntityTooLarge',
|
33
|
+
414 => 'RequestURITooLong',
|
34
|
+
415 => 'UnsupportedMediaType',
|
35
|
+
416 => 'RequestedRangeNotSatisfiable',
|
36
|
+
417 => 'ExpectationFailed',
|
37
|
+
418 => 'ImATeapot',
|
38
|
+
421 => 'TooManyConnectionsFromThisIP',
|
39
|
+
426 => 'UpgradeRequired',
|
40
|
+
450 => 'BlockedByWindowsParentalControls',
|
41
|
+
494 => 'RequestHeaderTooLarge',
|
42
|
+
497 => 'HTTPToHTTPS',
|
43
|
+
499 => 'ClientClosedRequest',
|
44
|
+
|
45
|
+
500 => 'InternalServerError',
|
46
|
+
501 => 'NotImplemented',
|
47
|
+
502 => 'BadGateway',
|
48
|
+
503 => 'ServiceUnavailable',
|
49
|
+
504 => 'GatewayTimeout',
|
50
|
+
505 => 'HTTPVersionNotSupported',
|
51
|
+
506 => 'VariantAlsoNegotiates',
|
52
|
+
510 => 'NotExtended'
|
53
|
+
}
|
54
|
+
|
55
|
+
ERRORS = HTTP_STATUSES.inject({}) do |sum, error|
|
56
|
+
status, name = error
|
57
|
+
sum[status] = Errors.const_set(name, Class.new(ServerError))
|
58
|
+
sum
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Client
|
4
|
+
class Response
|
5
|
+
attr_reader :status, :body, :headers
|
6
|
+
|
7
|
+
def initialize(status, body, headers = {})
|
8
|
+
@status, @body, @headers = status, body, headers
|
9
|
+
@body = body.force_encoding('UTF-8') if body.respond_to?(:force_encoding)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Client
|
4
|
+
module Selector
|
5
|
+
class Base
|
6
|
+
def select_from
|
7
|
+
raise NoMethodError, "Implement this method in the selector implementation."
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Random < Base
|
12
|
+
def select_from(connections)
|
13
|
+
connections.to_a.sample
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class RoundRobin < Base
|
18
|
+
def select_from(connections)
|
19
|
+
@current = @current.nil? ? 0 : @current + 1
|
20
|
+
@current = 0 if @current >= connections.size
|
21
|
+
connections[@current]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Configuration
|
4
|
+
attr_accessor :resurrect_timeout, :retry_on_failure, :connection_options,
|
5
|
+
:serializer, :log, :selector, :user, :password
|
6
|
+
|
7
|
+
attr_writer :logger
|
8
|
+
attr_reader :hosts
|
9
|
+
|
10
|
+
class Host
|
11
|
+
DEFAULT = ['http://localhost:8086'].freeze
|
12
|
+
DEFAULT_PORT = 8086
|
13
|
+
DEFAULT_PROTOCOL = 'http'.freeze
|
14
|
+
|
15
|
+
def initialize(source)
|
16
|
+
@source = to_hash(source)
|
17
|
+
end
|
18
|
+
|
19
|
+
def build
|
20
|
+
result = "#{protocol}://"
|
21
|
+
result << "#{user}:#{password}@" if user
|
22
|
+
result << "#{host}:#{port}"
|
23
|
+
result << path if path
|
24
|
+
result
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :source
|
30
|
+
|
31
|
+
def to_hash(source)
|
32
|
+
case source
|
33
|
+
when String
|
34
|
+
source =~ /^[a-z]+\:\/\// ? to_hash(URI.parse(source)) : Hash[[:host, :port].zip(source.split(?:))]
|
35
|
+
when URI
|
36
|
+
{
|
37
|
+
scheme: source.scheme,
|
38
|
+
user: source.user,
|
39
|
+
password: source.password,
|
40
|
+
host: source.host,
|
41
|
+
path: source.path,
|
42
|
+
port: source.port.to_s
|
43
|
+
}
|
44
|
+
when Hash
|
45
|
+
source
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Please pass host as a String, URI or Hash -- #{source.class} given."
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def protocol
|
52
|
+
source[:scheme] || DEFAULT_PROTOCOL
|
53
|
+
end
|
54
|
+
|
55
|
+
def port
|
56
|
+
source[:port] || DEFAULT_PORT
|
57
|
+
end
|
58
|
+
|
59
|
+
[:host, :user, :password, :path].each do |method|
|
60
|
+
define_method(method) do
|
61
|
+
source[method]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
DEFAULT_LOGGER = ->{
|
67
|
+
require 'logger'
|
68
|
+
logger = Logger.new(STDERR)
|
69
|
+
logger.progname = 'influxdb'
|
70
|
+
logger.formatter = ->(severity, datetime, progname, msg){ "#{datetime}: #{msg}\n" }
|
71
|
+
logger
|
72
|
+
}
|
73
|
+
|
74
|
+
def initialize
|
75
|
+
@log = false
|
76
|
+
@user = 'root'
|
77
|
+
@password = 'root'
|
78
|
+
@serializer = MultiJson
|
79
|
+
@connection_options = {}
|
80
|
+
@connection_block = nil
|
81
|
+
@retry_on_failure = false
|
82
|
+
@resurrect_timeout = 60
|
83
|
+
@hosts = Host::DEFAULT
|
84
|
+
@selector = Client::Selector::RoundRobin.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def logger
|
88
|
+
@logger ||= log ? DEFAULT_LOGGER.call : nil
|
89
|
+
end
|
90
|
+
|
91
|
+
def hosts=(value)
|
92
|
+
@hosts = Array.wrap(value).map(&method(:normalize_host))
|
93
|
+
end
|
94
|
+
|
95
|
+
def connection_block(&block)
|
96
|
+
if block_given?
|
97
|
+
@connection_block = block
|
98
|
+
else
|
99
|
+
@connection_block
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def dup
|
104
|
+
clone = super
|
105
|
+
clone.connection_options = connection_options.dup
|
106
|
+
clone
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def normalize_host(host)
|
112
|
+
Host.new(host).build
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
class Database
|
4
|
+
attr_reader :client, :name
|
5
|
+
|
6
|
+
def initialize(client, name)
|
7
|
+
@client = client
|
8
|
+
@name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def series
|
12
|
+
@series ||= Namespaces::Series.new(client, name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def users
|
16
|
+
@users ||= Namespaces::Users.new(client, name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def continuous_queries
|
20
|
+
@continuous_queries ||= Namespaces::ContinuousQueries.new(client, name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def shard_spaces
|
24
|
+
@shard_spaces ||= Namespaces::ShardSpaces.new(client, name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'namespaces/base'
|
2
|
+
require_relative 'namespaces/with_database'
|
3
|
+
require_relative 'namespaces/databases'
|
4
|
+
require_relative 'namespaces/series'
|
5
|
+
require_relative 'namespaces/users'
|
6
|
+
require_relative 'namespaces/continuous_queries'
|
7
|
+
require_relative 'namespaces/shard_spaces'
|
8
|
+
require_relative 'namespaces/cluster_admins'
|
9
|
+
require_relative 'namespaces/servers'
|
10
|
+
require_relative 'namespaces/shards'
|
11
|
+
|
12
|
+
module Influxdb
|
13
|
+
module Api
|
14
|
+
module Namespaces
|
15
|
+
def databases(name = nil)
|
16
|
+
if name
|
17
|
+
Database.new(self, name)
|
18
|
+
else
|
19
|
+
@databases ||= Databases.new(self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
alias_method :dbs, :databases
|
23
|
+
|
24
|
+
def cluster_admins
|
25
|
+
@cluster_admins ||= ClusterAdmins.new(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def servers
|
29
|
+
@servers ||= Servers.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
def shards
|
33
|
+
@shards ||= Shards.new(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def version
|
37
|
+
ServerVersion.new(perform_request('get', '/ping').headers['x-influxdb-version'])
|
38
|
+
end
|
39
|
+
|
40
|
+
def sync?
|
41
|
+
config.serializer.load(perform_request('get', '/sync').body)
|
42
|
+
end
|
43
|
+
alias_method :cluster_synchronized?, :sync?
|
44
|
+
|
45
|
+
def interfaces
|
46
|
+
perform_request('get', '/interfaces').body
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Influxdb
|
2
|
+
module Api
|
3
|
+
module Namespaces
|
4
|
+
class Base
|
5
|
+
attr_reader :client
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :_resource_path
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def resource_path(value)
|
13
|
+
self._resource_path = value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(client)
|
18
|
+
@client = client
|
19
|
+
end
|
20
|
+
|
21
|
+
def all
|
22
|
+
perform_get(resource_path)
|
23
|
+
end
|
24
|
+
|
25
|
+
def create(attributes)
|
26
|
+
perform_post(resource_path, {}, attributes)
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(name)
|
31
|
+
perform_delete(resource_path(name))
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def resource_path(*args)
|
38
|
+
[path_prefix, self.class._resource_path, path_postfix, args].compact.flatten.join(?/).squeeze(?/)
|
39
|
+
end
|
40
|
+
|
41
|
+
def path_prefix
|
42
|
+
end
|
43
|
+
|
44
|
+
def path_postfix
|
45
|
+
end
|
46
|
+
|
47
|
+
def perform_get(path, params = {})
|
48
|
+
client.perform_request('get', path, params || {}).body
|
49
|
+
end
|
50
|
+
|
51
|
+
def perform_post(path, params, body)
|
52
|
+
client.perform_request('post', path, params || {}, body).body
|
53
|
+
end
|
54
|
+
|
55
|
+
def perform_delete(path, params = {}, body = nil)
|
56
|
+
client.perform_request('delete', path, params || {}, body).body
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|