druid_config 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a03eb8b4f7df4223fe098516a23443beac52be00
4
- data.tar.gz: 230450c3d105e2327c681f1bc1beb225926361be
3
+ metadata.gz: 34faeb23be9dfd54181862f172bb5db8b794f489
4
+ data.tar.gz: 58c09b7c65c33be02e1b2cf0f9ca8eaa3754666f
5
5
  SHA512:
6
- metadata.gz: 151efb283126cbf585549a0e1d0a7f766f48c51e3f21e18ab373c34d59a247c64fbcc1188157ccaadb7b5940ccdcc480c24b87f33a2f0e890e019be817b9bcab
7
- data.tar.gz: db35a7cc044f47bb4de83ea1467e35186389471485f71f48e3f4363087dc8f9326150a0df93a7844d901b804bf38348d51ab2cfb452a2aa708240cbd08a5ba76
6
+ metadata.gz: 64062d2ad8ec0abc2487a003feb746d175aaf6cc8b47b703fbc1544e1a59bd1089209c6d61d164678cbe469884ebefff97f0114cec7884bc63daea73b44df45f
7
+ data.tar.gz: 7149d8613c814c63ae21ccae898a0205dcbe479a5b0973f757d462a4d8b4d47a5ebefff5fd1cda6527b73e61222c68ff221dc893523735ae33e579617422b129
data/README.md CHANGED
@@ -44,6 +44,8 @@ Call methods defined in `DruidConfig::Cluster` to access to the data. To get mor
44
44
  * `realtimes`: realtime nodes
45
45
  * `workers`: worker nodes
46
46
  * `physical_workers`: array of URIs of worker nodes
47
+ * `running_tasks`, `pending_tasks`, `waiting_tasks`, `complete_tasks`: tasks in the cluster based in their status
48
+ * `task`: load a task based on an identifier
47
49
  * `services`: Hash with physical nodes and the services they are running
48
50
 
49
51
  ## Entities
@@ -55,6 +57,7 @@ Some methods return an instance of an `Entity` class. These entities provide mul
55
57
  * [Tier](https://github.com/redBorder/druid_config/blob/master/lib/druid_config/entities/tier.rb)
56
58
  * [Node](https://github.com/redBorder/druid_config/blob/master/lib/druid_config/entities/node.rb)
57
59
  * [Worker](https://github.com/redBorder/druid_config/blob/master/lib/druid_config/entities/worker.rb)
60
+ * [Task](https://github.com/redBorder/druid_config/blob/master/lib/druid_config/entities/task.rb)
58
61
 
59
62
  ## Exceptions
60
63
 
data/lib/druid_config.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  # Global library
2
2
  require 'httparty'
3
+ require 'iso8601'
4
+ require 'delegate'
5
+ require 'json'
6
+ require 'net/http'
3
7
 
4
8
  # Classes
5
9
  require 'druid_config/zk'
6
10
  require 'druid_config/version'
7
11
  require 'druid_config/util'
8
12
  require 'druid_config/entities/segment'
13
+ require 'druid_config/entities/rule'
14
+ require 'druid_config/entities/rule_collection'
9
15
  require 'druid_config/entities/task'
10
16
  require 'druid_config/entities/worker'
11
17
  require 'druid_config/entities/node'
@@ -158,6 +158,17 @@ module DruidConfig
158
158
  datasources.select { |el| el.name == datasource }
159
159
  end
160
160
 
161
+ #
162
+ # Return default datasource. This datasource hasn't got metadata
163
+ # associated. It's only used to read and apply default rules.
164
+ #
165
+ def default_datasource
166
+ DruidConfig::Entities::DataSource.new(
167
+ { 'name' => DruidConfig::Entities::DataSource::DEFAULT_DATASOURCE,
168
+ 'properties' => {} },
169
+ {})
170
+ end
171
+
161
172
  # Rules
162
173
  # -----------------
163
174
 
@@ -165,9 +176,16 @@ module DruidConfig
165
176
  # Return the rules applied to a cluster
166
177
  #
167
178
  def rules
179
+ rules = DruidConfig::Entities::RuleCollection.new
168
180
  secure_query do
169
- self.class.get('/rules')
181
+ self.class.get('/rules').each do |datasource, ds_rules|
182
+ ds_rules.each do |rule|
183
+ rules << DruidConfig::Entities::Rule.parse(rule, datasource)
184
+ end
185
+ end
170
186
  end
187
+ # Return initialized rules
188
+ rules
171
189
  end
172
190
 
173
191
  # Tiers
@@ -12,6 +12,9 @@ module DruidConfig
12
12
 
13
13
  attr_reader :name, :properties, :load_status
14
14
 
15
+ # Name of default datasource
16
+ DEFAULT_DATASOURCE = '_default'.freeze
17
+
15
18
  #
16
19
  # Initialize a DataSource
17
20
  #
@@ -75,17 +78,76 @@ module DruidConfig
75
78
  # Rules
76
79
  # -----------------
77
80
  def rules(params = '')
81
+ return @rules if @rules
82
+ @rules = DruidConfig::Entities::RuleCollection.new
78
83
  secure_query do
79
- self.class.get("/rules/#{@name}?#{params}")
84
+ self.class.get("/rules/#{@name}?#{params}").each do |rule|
85
+ @rules << DruidConfig::Entities::Rule.parse(rule)
86
+ end
87
+ end
88
+ @rules
89
+ end
90
+
91
+ #
92
+ # Apply given rules to the datasource
93
+ #
94
+ # == Paremeters:
95
+ # rules::
96
+ # RuleCollection of rules
97
+ #
98
+ # == Returns:
99
+ # Boolean indicating the status of the request
100
+ #
101
+ def update_rules(new_rules)
102
+ if post_rules(new_rules)
103
+ @rules = new_rules
104
+ true
105
+ else
106
+ false
80
107
  end
81
108
  end
82
109
 
110
+ #
111
+ # Save current rules
112
+ #
113
+ # == Returns:
114
+ # Boolean indicating the status of the request
115
+ #
116
+ def save_rules
117
+ post_rules(rules)
118
+ end
119
+
83
120
  def history_rules(interval)
84
121
  secure_query do
85
122
  self.class.get("/rules/#{@name}/history"\
86
123
  "?interval=#{interval}")
87
124
  end
88
125
  end
126
+
127
+ private
128
+
129
+ #
130
+ # Save rules of this data source
131
+ #
132
+ # == Paremeters:
133
+ # rules::
134
+ # RuleCollection of rules
135
+ #
136
+ # == Returns:
137
+ # Boolean indicating the status of the request
138
+ #
139
+ def post_rules(new_rules)
140
+ fail(ArgumentError, 'Rules must be a RuleCollection instance') unless
141
+ new_rules.is_a?(RuleCollection)
142
+ uri = URI("#{self.class.base_uri}/rules/#{name}")
143
+ http = Net::HTTP.new(uri.host, uri.port)
144
+ request = Net::HTTP::Post.new(uri.request_uri)
145
+ request['Content-Type'] = 'application/json'
146
+ request.body = new_rules.map(&:to_h).to_json
147
+ response = http.request(request)
148
+ # Check statys
149
+ response.code.to_i == 200
150
+ end
89
151
  end
90
152
  end
91
153
  end
@@ -60,7 +60,8 @@ module DruidConfig
60
60
  # Calculate free space
61
61
  #
62
62
  def free
63
- max_size - size
63
+ return @free if @free
64
+ @free = (max_size - size) > 0 ? (max_size - size) : 0
64
65
  end
65
66
 
66
67
  #
@@ -0,0 +1,164 @@
1
+ module DruidConfig
2
+ module Entities
3
+ #
4
+ # Rule class
5
+ #
6
+ class Rule
7
+ # Variables
8
+ attr_reader :datasource, :type, :time_type, :replicants, :period,
9
+ :interval
10
+
11
+ # Identifier for type
12
+ FOREVER_DRUID_STRING = 'Forever'
13
+ INTERVAL_DRUID_STRING = 'ByInterval'
14
+ PERIOD_DRUID_STRING = 'ByPeriod'
15
+
16
+ #
17
+ # Parse data from a Druid API response an initialize an object of
18
+ # Rule class
19
+ #
20
+ # == Parameters:
21
+ # datasource::
22
+ # String with the name of the datsource
23
+ # data::
24
+ # Hash provided by the API
25
+ #
26
+ # == Returns:
27
+ # Rule instance
28
+ #
29
+ def self.parse(data, datasource = nil)
30
+ type, time_type = detect_type(data['type'])
31
+ options = { replicants: data['tieredReplicants'] }
32
+ options.merge!(datasource: datasource) if datasource
33
+ if time_type == :period
34
+ options.merge!(period: data['period'])
35
+ elsif time_type == :interval
36
+ options.merge!(interval: data['interval'])
37
+ end
38
+ # Instance the class
39
+ new(type, time_type, options)
40
+ end
41
+
42
+ #
43
+ # Initialize a Rule object. This constructor accepts a Hash with
44
+ # format defined in:
45
+ # http://druid.io/docs/latest/operations/rule-configuration.html
46
+ #
47
+ # == Parameters:
48
+ # datasource::
49
+ # String with the name of the data source
50
+ # type::
51
+ # Type of the rule, it can be :drop or :load
52
+ # time_type::
53
+ # Time reference. It can be :forever, :period or :interval
54
+ # options::
55
+ # Hash with extra data to the rules.
56
+ # - replicants: Hash with format
57
+ # { 'tier' => NumberOfReplicants, 'tier' => ... }
58
+ # - period: String with a period in ISO8601 format.
59
+ # Only available when type is :period.
60
+ # - interval: String with a interval in ISO8601 format.
61
+ # Only available when type is :interval.
62
+ # - datasource: Name of the datasource
63
+ #
64
+ def initialize(type, time_type, options = {})
65
+ @type = type
66
+ @time_type = time_type
67
+ @datasource = options[:datasource]
68
+ @replicants = options[:replicants]
69
+ if period?
70
+ @period = ISO8601::Duration.new(options[:period])
71
+ elsif interval?
72
+ # TODO: https://github.com/arnau/ISO8601/issues/15
73
+ @interval = options[:interval]
74
+ end
75
+ end
76
+
77
+ #
78
+ # Functions to check the rule type
79
+ #
80
+ %w(drop load).each do |rule|
81
+ define_method("#{rule}?") do
82
+ @type == rule.to_sym
83
+ end
84
+ end
85
+
86
+ #
87
+ # Functions to check how rule time is defined
88
+ #
89
+ %w(interval forever period).each do |time|
90
+ define_method("#{time}?") do
91
+ @time_type == time.to_sym
92
+ end
93
+ end
94
+
95
+ #
96
+ # Return the rule as Hash format
97
+ #
98
+ # == Returns:
99
+ # Hash
100
+ #
101
+ def to_h
102
+ base = { type: type_to_druid }
103
+ base.merge!(tieredReplicants: @replicants) if @replicants
104
+ if period?
105
+ base.merge(period: @period.to_s)
106
+ elsif interval?
107
+ base.merge(interval: @interval.to_s)
108
+ else
109
+ base
110
+ end
111
+ end
112
+
113
+ #
114
+ # Return the rule as valid JSON for Druid
115
+ #
116
+ # == Returns:
117
+ # JSON String
118
+ #
119
+ def to_json
120
+ to_h.to_json
121
+ end
122
+
123
+ #
124
+ # Detect the type of the rule based on 'type' field. This method will
125
+ # detect if is a drop/load rule and how it defines time.
126
+ #
127
+ # == Parameters:
128
+ # type_to_parse::
129
+ # String with the content of type field
130
+ #
131
+ def self.detect_type(type_to_parse)
132
+ type = type_to_parse.starts_with?('drop') ? :drop : :load
133
+ time_type = case type_to_parse.gsub(type.to_s, '')
134
+ when INTERVAL_DRUID_STRING
135
+ :interval
136
+ when FOREVER_DRUID_STRING
137
+ :forever
138
+ when PERIOD_DRUID_STRING
139
+ :period
140
+ end
141
+ [type, time_type]
142
+ end
143
+
144
+ private
145
+
146
+ #
147
+ # Convert the type to an String Druid can identify
148
+ #
149
+ # == Returns:
150
+ # String with the type of the rule
151
+ #
152
+ def type_to_druid
153
+ time = if period?
154
+ PERIOD_DRUID_STRING
155
+ elsif interval?
156
+ INTERVAL_DRUID_STRING
157
+ else
158
+ FOREVER_DRUID_STRING
159
+ end
160
+ "#{@type}#{time}"
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,65 @@
1
+ module DruidConfig
2
+ module Entities
3
+ #
4
+ # Rule set of a data source
5
+ #
6
+ class RuleCollection < Array
7
+ #
8
+ # Check the consistency of the rules. For example, if you define the
9
+ # following rules:
10
+ #
11
+ # 1 - LOAD ByPeriod PT12M replicants -> { _default_tier => 1 }
12
+ # 2 - LOAD ByPeriod PT3M replicants -> { _default_tier => 1 }
13
+ #
14
+ # The second rule never be applied.
15
+ #
16
+ # This method don't raise any exception and your Druid installation will
17
+ # work unless there are an inconsistence. The purpose of this method is
18
+ # to advise you could be wrong about rules
19
+ #
20
+ # == Returns:
21
+ # A boolean. True when the rules are consistent.
22
+ #
23
+ def consistent?
24
+ # TODO: implement this method
25
+ true
26
+ end
27
+
28
+ #
29
+ # Return the collection of rules as a valid JSON for Druid
30
+ #
31
+ # == Parameters:
32
+ # include_datasources::
33
+ # True if you want to include the name of the datasources as keys
34
+ # (False by default)
35
+ #
36
+ # == Returns:
37
+ # JSON String
38
+ #
39
+ def to_json(include_datasources = false)
40
+ return to_json_with_datasources if include_datasources
41
+ map(&:to_h).to_json
42
+ end
43
+
44
+ private
45
+
46
+ #
47
+ # Return a JSON string with the datasources and the rules associated to
48
+ # them
49
+ #
50
+ # == Returns:
51
+ # JSON string with format:
52
+ # { 'datasource' => [ { "type" => ... }, ...], 'datasource2' => [...] }
53
+ #
54
+ def to_json_with_datasources
55
+ rules_with_ds = {}
56
+ map do |rule|
57
+ rules_with_ds[rule.datasource] ||= []
58
+ rules_with_ds[rule.datasource] << rule.to_h
59
+ end
60
+ rules_with_ds.to_json
61
+ end
62
+ end
63
+ end
64
+ end
65
+
@@ -25,7 +25,8 @@ module DruidConfig
25
25
  end
26
26
 
27
27
  def free
28
- @free ||= (max_size - size)
28
+ return @free if @free
29
+ @free = (max_size - size) > 0 ? (max_size - size) : 0
29
30
  end
30
31
 
31
32
  def used_percent
@@ -37,7 +37,8 @@ module DruidConfig
37
37
  # Return free capacity
38
38
  #
39
39
  def free
40
- @free ||= (capacity - capacity_used)
40
+ return @free if @free
41
+ @free = (capacity - capacity_used) > 0 ? (capacity - capacity_used) : 0
41
42
  end
42
43
 
43
44
  #
@@ -0,0 +1,10 @@
1
+ module DruidConfig
2
+ module Validators
3
+ #
4
+ # Validator of rule class.
5
+ #
6
+ class RuleValidator
7
+
8
+ end
9
+ end
10
+ end
@@ -4,7 +4,7 @@
4
4
  module DruidConfig
5
5
  module Version
6
6
  # Version of the gem
7
- VERSION = '0.2.0'
7
+ VERSION = '0.3.0'
8
8
 
9
9
  # Base URI foor coordinator queries
10
10
  API_VERSION = 'v1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: druid_config
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Angel M Miguel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-30 00:00:00.000000000 Z
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zk
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.8.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: iso8601
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.8.7
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.8.7
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -151,11 +165,13 @@ files:
151
165
  - lib/druid_config/entities/data_source.rb
152
166
  - lib/druid_config/entities/node.rb
153
167
  - lib/druid_config/entities/rule.rb
168
+ - lib/druid_config/entities/rule_collection.rb
154
169
  - lib/druid_config/entities/segment.rb
155
170
  - lib/druid_config/entities/task.rb
156
171
  - lib/druid_config/entities/tier.rb
157
172
  - lib/druid_config/entities/worker.rb
158
173
  - lib/druid_config/util.rb
174
+ - lib/druid_config/validators/rule_validator.rb
159
175
  - lib/druid_config/version.rb
160
176
  - lib/druid_config/zk.rb
161
177
  - spec/cluster_spec.rb