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,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,15 @@
1
+ class Array
2
+ class << self
3
+ unless method_defined?(:wrap)
4
+ def wrap(object)
5
+ if object.nil?
6
+ []
7
+ elsif object.respond_to?(:to_ary)
8
+ object.to_ary || [object]
9
+ else
10
+ [object]
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -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