flydata 0.5.0 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0bbdc5f5871df8b3fec4c8c92abd1fdb6b6b24f6
4
- data.tar.gz: 0be09c4771db44cac9c3229251598f6f5c3c23fd
3
+ metadata.gz: 3363c696e28b167255482e1d6b7352d5e3989786
4
+ data.tar.gz: 57d1039674d07396d58b2cf32d25c5c38db703ca
5
5
  SHA512:
6
- metadata.gz: 3bdacc04e29100c441e7e1eb1660eb9763e2566f0ac05846a7cc85ac2067e4f0171c41d95e4a12ae5fa7b9c3720b5583040191a68b669b392e360fa58be79abb
7
- data.tar.gz: 932a0de391228f576f389c731f312108931be9473875fe8265cc982d58771a6ea20671a762eeaf7b30a5aefbdfa0d60bb4572f409635f757e2bd900fad65e966
6
+ metadata.gz: 24e8879e214ec3b0cfa21d7b725e05bca66b4c668f59d3bfc5869285e70d1a92f97971002566f9d7e65332d91897561a20ffab26916ee7ce35c163e25066546a
7
+ data.tar.gz: 6303e50004f8d927867892a94e309d8e578cee1ed633f2768bae4470aca808cd9945ff2694ac220a07d4e20bea35df2df194963475ee971417910c22bdc6914b
data/Gemfile CHANGED
@@ -13,7 +13,7 @@ gem "slop", '~> 3.4', '>= 3.4.6'
13
13
  gem "treetop", '~> 1.5', '>= 1.5.3'
14
14
  gem "sys-filesystem", '~> 1.1', '>= 1.1.3'
15
15
  gem "io-console", '~> 0.4.2', '>= 0.4.2'
16
- gem "kodama", '~> 0.1.2', '>= 0.1.6'
16
+ gem "kodama", '~> 0.1.2', '>= 0.1.7'
17
17
  gem "serverengine", '~> 1.5'
18
18
 
19
19
  group :development do
data/Gemfile.lock CHANGED
@@ -61,8 +61,8 @@ GEM
61
61
  rdoc
62
62
  json (1.8.1)
63
63
  jwt (1.0.0)
64
- kodama (0.1.6)
65
- ruby-binlog (~> 1.0, >= 1.0.4)
64
+ kodama (0.1.7)
65
+ ruby-binlog (~> 1.0, >= 1.0.6)
66
66
  method_source (0.8.2)
67
67
  mime-types (2.3)
68
68
  minitest (4.7.5)
@@ -105,7 +105,7 @@ GEM
105
105
  rspec-mocks (3.0.3)
106
106
  rspec-support (~> 3.0.0)
107
107
  rspec-support (3.0.3)
108
- ruby-binlog (1.0.4)
108
+ ruby-binlog (1.0.6)
109
109
  ruby-prof (0.15.1)
110
110
  serverengine (1.5.10)
111
111
  sigdump (~> 0.2.2)
@@ -135,7 +135,7 @@ DEPENDENCIES
135
135
  io-console (~> 0.4.2, >= 0.4.2)
136
136
  jeweler (~> 1.8, >= 1.8.8)
137
137
  json (~> 1.8, >= 1.8.0)
138
- kodama (~> 0.1.2, >= 0.1.6)
138
+ kodama (~> 0.1.2, >= 0.1.7)
139
139
  mysql2 (~> 0.3, >= 0.3.17)
140
140
  protected_attributes (~> 1.0, >= 1.0.8)
141
141
  pry
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
@@ -14,3 +14,4 @@ spec/reports
14
14
  test/tmp
15
15
  test/version_tmp
16
16
  tmp
17
+ /vendor/
data/flydata-core/Gemfile CHANGED
@@ -1,11 +1,14 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+
3
4
  # for dependencies
5
+ gem 'aws-sdk', "1.18.0"
6
+
4
7
  group :development, :test do
5
8
  gem 'timecop'
6
9
  gem 'ruby-prof'
7
10
  gem 'rubocop'
11
+ gem 'mysql2'
8
12
  gem 'rspec', '~> 3.1'
9
13
  gem 'simplecov', :require => false
10
14
  end
11
-
@@ -4,9 +4,16 @@ GEM
4
4
  ast (2.0.0)
5
5
  astrolabe (1.3.0)
6
6
  parser (>= 2.2.0.pre.3, < 3.0)
7
+ aws-sdk (1.18.0)
8
+ json (~> 1.4)
9
+ nokogiri (< 1.6.0)
10
+ uuidtools (~> 2.1)
7
11
  diff-lcs (1.2.5)
8
12
  docile (1.1.5)
13
+ json (1.8.2)
9
14
  multi_json (1.10.1)
15
+ mysql2 (0.3.18)
16
+ nokogiri (1.5.11)
10
17
  parser (2.2.0.pre.8)
11
18
  ast (>= 1.1, < 3.0)
12
19
  slop (~> 3.4, >= 3.4.5)
@@ -39,11 +46,14 @@ GEM
39
46
  simplecov-html (0.8.0)
40
47
  slop (3.6.0)
41
48
  timecop (0.7.1)
49
+ uuidtools (2.1.5)
42
50
 
43
51
  PLATFORMS
44
52
  ruby
45
53
 
46
54
  DEPENDENCIES
55
+ aws-sdk (= 1.18.0)
56
+ mysql2
47
57
  rspec (~> 3.1)
48
58
  rubocop
49
59
  ruby-prof
@@ -118,34 +118,57 @@ module FlydataCore
118
118
  'binlog_format'=>'ROW',
119
119
  'binlog_checksum'=>'NONE',
120
120
  'log_bin_use_v1_row_events'=>'ON',
121
- 'log_slave_updates'=>'ON'
121
+ 'log_slave_updates'=>'ON',
122
+ # parameter => {"comparison sign"=>minimum value}
123
+ # TODO: Handled the error message of following items as warning
124
+ #'net_read_timeout'=>{'>'=>600},
125
+ #'net_write_timeout'=>{'>'=>600},
126
+ #'wait_timeout'=>{'>'=>60}
122
127
  }
128
+ OPTIONAL_SYS_VAR = %w(binlog_checksum log_bin_use_v1_row_events)
123
129
 
124
130
  def check_result(result, option = @option)
125
131
  errors = {}
126
132
  param_hash = convert_result_to_hash(result)
127
133
 
128
- SYS_VAR_TO_CHECK.each_key do |sys_var|
129
- if param_hash.has_key?(sys_var)
130
- actual_val = param_hash[sys_var]
131
- expected_val = SYS_VAR_TO_CHECK[sys_var]
132
- unless actual_val == expected_val
133
- errors[sys_var] = actual_val
134
- end
135
- elsif not %w(binlog_checksum log_bin_use_v1_row_events).include?(sys_var)
136
- # Mark variables that do not exist as error
137
- errors[sys_var] = false
138
- end
139
- end
134
+ compare_sys_var_values(param_hash, SYS_VAR_TO_CHECK, errors, OPTIONAL_SYS_VAR)
140
135
 
141
136
  unless errors.empty?
142
137
  error_explanation = ""
143
138
  errors.each_key do |err_key|
144
- error_explanation << "\n * #{err_key} is #{errors[err_key]} but should be #{SYS_VAR_TO_CHECK[err_key]}"
139
+ if SYS_VAR_TO_CHECK[err_key].is_a?(Hash)
140
+ error_explanation << "\n * #{err_key} is #{errors[err_key]} but should be at least #{SYS_VAR_TO_CHECK[err_key].values.first}"
141
+ else
142
+ error_explanation << "\n * #{err_key} is #{errors[err_key]} but should be #{SYS_VAR_TO_CHECK[err_key]}"
143
+ end
145
144
  end
146
145
  raise FlydataCore::MysqlCompatibilityError,
147
146
  "These system variable(s) are not the correct value: #{error_explanation}\n" +
148
- " Please change these system variables for FlyData Sync to run correctly"
147
+ " Please change these system variables for FlyData Sync to run"
148
+ end
149
+ end
150
+
151
+ private
152
+ def compare_sys_var_values(input_value_hash, expected_value_hash, errors, exception_arr)
153
+ expected_value_hash.each_key do |exp_val|
154
+ if input_value_hash.has_key?(exp_val)
155
+ actual_val = input_value_hash[exp_val]
156
+ compare_sym = expected_value_hash[exp_val].is_a?(Hash) ? expected_value_hash[exp_val].keys.first : "="
157
+ case compare_sym
158
+ when "="
159
+ expected_val = expected_value_hash[exp_val]
160
+ unless actual_val == expected_val
161
+ errors[exp_val] = actual_val
162
+ end
163
+ when ">"
164
+ expected_val = expected_value_hash[exp_val].values.first
165
+ unless actual_val.to_i >= expected_val.to_i
166
+ errors[exp_val] = actual_val
167
+ end
168
+ end
169
+ elsif not exception_arr.include?(exp_val)
170
+ errors[exp_val] = false
171
+ end
149
172
  end
150
173
  end
151
174
  end
@@ -181,6 +204,34 @@ module FlydataCore
181
204
  end
182
205
  end
183
206
 
207
+ class PrimaryKeyChecker < MysqlCompatibilityChecker
208
+ PK_CHECK_QUERY_TMPLT = <<EOT
209
+ SELECT k.table_name as table_name
210
+ FROM information_schema.table_constraints t
211
+ JOIN information_schema.key_column_usage k
212
+ USING(constraint_name,table_schema,table_name)
213
+ WHERE t.constraint_type='PRIMARY KEY'
214
+ AND t.table_schema='%{database}'
215
+ AND t.table_name in (%{table_names})
216
+ GROUP BY k.table_name;
217
+ EOT
218
+ def create_query(option = @option)
219
+ PK_CHECK_QUERY_TMPLT % {database: option[:database], table_names: option[:tables].collect{|tn| "'#{tn}'"}.join(',')}
220
+ end
221
+
222
+ def check_result(result, option = @option)
223
+ pk_tables = []
224
+ result.each {|r| pk_tables << r['table_name']}
225
+ missing_pk_tables = option[:tables] - pk_tables
226
+
227
+ unless missing_pk_tables.empty?
228
+ raise FlydataCore::MysqlCompatibilityError,
229
+ "Primary key is required for tables to sync. " +
230
+ "Add primary key or remove following tables from data entry: #{missing_pk_tables.join(", ")}"
231
+ end
232
+ end
233
+ end
234
+
184
235
  class NonRdsRetentionChecker < MysqlCompatibilityChecker
185
236
  include MysqlVariablesHandling
186
237
 
@@ -87,6 +87,19 @@ EOS
87
87
  schema_name.to_s.empty? ? "\"#{table_name}\"" : "\"#{schema_name}\".\"#{table_name}\""
88
88
  end
89
89
 
90
+ def self.fq_table_name(table_name, schema_name)
91
+ idx = table_name.rindex('.')
92
+ if (idx)
93
+ # table name has schame qualifier. Remove it.
94
+ table_name = table_name[idx+1..-1]
95
+ end
96
+
97
+ result =
98
+ schema_name.to_s.empty? ? table_name : "#{schema_name}.#{table_name}"
99
+
100
+ convert_to_valid_table_name(result)
101
+ end
102
+
90
103
  def self.flydata_ctl_table_for_ddl(schema_name, ctl_table_type = :columns)
91
104
  table_name = case ctl_table_type
92
105
  when :columns; FLYDATA_CTL_COLUMNS_TABLE
@@ -0,0 +1,28 @@
1
+ module FlydataCore
2
+
3
+ module WrapperSingleForwardable
4
+ # Delegates a method call `delegator` to the given `accessor` like the
5
+ # original `def_single_delegator` does. In addition, it wraps the returned
6
+ # object (or each object in an array) with the caller's own instance.
7
+ def def_wrapper_single_delegator(accessor, delegator)
8
+ self.define_singleton_method(delegator) do |*args|
9
+ result = accessor.send(delegator, *args)
10
+ case result
11
+ when Array
12
+ result.collect{|res| self.new(res)}
13
+ when NilClass
14
+ nil
15
+ else
16
+ self.new(result)
17
+ end
18
+ end
19
+ end
20
+
21
+ def def_wrapper_single_delegators(accessor, *delegators)
22
+ delegators.each do |delegator|
23
+ def_wrapper_single_delegator(accessor, delegator)
24
+ end
25
+ end
26
+ end
27
+
28
+ end
@@ -1,9 +1,186 @@
1
1
  require 'spec_helper'
2
+ require 'flydata-core/mysql/compatibility_checker'
2
3
 
3
4
  module FlydataCore
4
5
  module Mysql
5
- describe SyncPermissionChecker do
6
+ describe CompatibilityChecker do
7
+ let(:database) { 'test_db' }
8
+ let(:tables) { %w(table_1 table_2 table_3) }
9
+ let(:option) do
10
+ { database: database, tables: tables }
11
+ end
6
12
 
13
+ describe PrimaryKeyChecker do
14
+ let(:subject_object) { described_class.new(option) }
15
+
16
+ describe '#create_query' do
17
+ subject { subject_object.create_query }
18
+ it { is_expected.to eq <<EOT
19
+ SELECT k.table_name as table_name
20
+ FROM information_schema.table_constraints t
21
+ JOIN information_schema.key_column_usage k
22
+ USING(constraint_name,table_schema,table_name)
23
+ WHERE t.constraint_type='PRIMARY KEY'
24
+ AND t.table_schema='test_db'
25
+ AND t.table_name in ('table_1','table_2','table_3')
26
+ GROUP BY k.table_name;
27
+ EOT
28
+ }
29
+ end
30
+
31
+ describe '#check_reesult' do
32
+ let(:result) { [] }
33
+ subject { subject_object.check_result(result) }
34
+
35
+ context 'when all tables have pk' do
36
+ let(:result) do
37
+ [ {"table_name" => "table_1"},
38
+ {"table_name" => "table_2"},
39
+ {"table_name" => "table_3"}, ]
40
+ end
41
+ it { expect{subject}.not_to raise_error }
42
+ end
43
+
44
+ context 'when some tables does not have pk' do
45
+ let(:result) { [{"table_name" => "table_2"} ] }
46
+ it do
47
+ expect{subject}.to raise_error {|e|
48
+ expect(e).to be_kind_of(FlydataCore::MysqlCompatibilityError)
49
+ expect(e.to_s.include?("table_1")).to be_truthy
50
+ expect(e.to_s.include?("table_2")).to be_falsey
51
+ expect(e.to_s.include?("table_3")).to be_truthy
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ describe BinlogParameterChecker do
60
+ let(:subject_object) { BinlogParameterChecker.new({}) }
61
+
62
+ describe "#check_result" do
63
+ let(:sys_var) do
64
+ [
65
+ {'Variable_name'=>'binlog_format','Value'=>'ROW'},
66
+ {'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
67
+ {'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
68
+ {'Variable_name'=>'log_slave_updates','Value'=>'ON'},
69
+ {'Variable_name'=>'net_read_timeout','Value'=>600},
70
+ {'Variable_name'=>'net_write_timeout','Value'=>600},
71
+ {'Variable_name'=>'wait_timeout','Value'=>60}
72
+ ]
73
+ end
74
+ subject { subject_object.check_result(sys_var, {}) }
75
+
76
+ context "where parameters are valid" do
77
+ it do
78
+ expect{subject}.to_not raise_error
79
+ end
80
+ end
81
+ context "where parameters are invalid" do
82
+ let(:sys_var) do
83
+ [
84
+ {'Variable_name'=>'binlog_format','Value'=>'MIXED'},
85
+ {'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
86
+ {'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
87
+ {'Variable_name'=>'log_slave_updates','Value'=>'ON'},
88
+ {'Variable_name'=>'net_read_timeout','Value'=>600},
89
+ {'Variable_name'=>'net_write_timeout','Value'=>600},
90
+ {'Variable_name'=>'wait_timeout','Value'=>30}
91
+ ]
92
+ end
93
+ it do
94
+ expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /binlog_format.*\n.*wait_timeout/)
95
+ end
96
+ end
97
+ end
98
+ describe "#compare_sys_var_values" do
99
+ let(:expected_val) do
100
+ {
101
+ :value_1 => 'foo',
102
+ :value_2 => 50,
103
+ :value_3 => {">"=>100}
104
+ }
105
+ end
106
+ let(:errors) { {} }
107
+ let(:exception_arr) { [] }
108
+ subject { subject_object.send(:compare_sys_var_values, input_val, expected_val, errors, exception_arr) }
109
+
110
+ shared_examples "expect correct errors from values" do
111
+ it do
112
+ subject
113
+ expect(errors).to eq( expecting_errors )
114
+ end
115
+ end
116
+
117
+ context "when getting valid parameters" do
118
+ let(:input_val) do
119
+ {
120
+ :value_1 => 'foo',
121
+ :value_2 => 50,
122
+ :value_3 => 200
123
+ }
124
+ end
125
+ let(:expecting_errors) { {} }
126
+ it_behaves_like "expect correct errors from values"
127
+ end
128
+ context "when getting one invalid exact parameters for int" do
129
+ let(:input_val) do
130
+ {
131
+ :value_1 => 'foo',
132
+ :value_2 => 20,
133
+ :value_3 => 100
134
+ }
135
+ end
136
+ let(:expecting_errors) { {value_2:20} }
137
+ it_behaves_like "expect correct errors from values"
138
+ end
139
+ context "when getting one invalid exact parameter for string" do
140
+ let(:input_val) do
141
+ {
142
+ :value_1 => 'fo',
143
+ :value_2 => 50,
144
+ :value_3 => 100
145
+ }
146
+ end
147
+ let(:expecting_errors) { {value_1:'fo'} }
148
+ it_behaves_like "expect correct errors from values"
149
+ end
150
+ context "when getting one invalid comparitive parameter that's lower than required" do
151
+ let(:input_val) do
152
+ {
153
+ :value_1 => 'foo',
154
+ :value_2 => 50,
155
+ :value_3 => 1
156
+ }
157
+ end
158
+ let(:expecting_errors) { {value_3:1} }
159
+ it_behaves_like "expect correct errors from values"
160
+ end
161
+ context "when getting a valid comparitive parameter that's higher than required" do
162
+ let(:input_val) do
163
+ {
164
+ :value_1 => 'foo',
165
+ :value_2 => 50,
166
+ :value_3 => 101
167
+ }
168
+ end
169
+ let(:expecting_errors) { {} }
170
+ it_behaves_like "expect correct errors from values"
171
+ end
172
+ context "when getting muliple invalid parameters" do
173
+ let(:input_val) do
174
+ {
175
+ :value_1 => 'fo',
176
+ :value_2 => 50,
177
+ :value_3 => 15
178
+ }
179
+ end
180
+ let(:expecting_errors) { {value_1:'fo', value_3:15} }
181
+ it_behaves_like "expect correct errors from values"
182
+ end
183
+ end
7
184
  end
8
185
  end
9
186
  end
@@ -896,6 +896,43 @@ EOS
896
896
 
897
897
  it_behaves_like "expecting no underscore in front of numbers"
898
898
  end
899
+
900
+ describe ".fq_table_name" do
901
+ subject { subject_object.fq_table_name(table_name, schema_name) }
902
+ context "with no schema name" do
903
+ let(:schema_name) { nil }
904
+ context "with a table name with no schema prefix" do
905
+ let(:table_name) { "test_table" }
906
+ it { is_expected.to eq "test_table" }
907
+ end
908
+ context "with a table name with a schema prefix" do
909
+ let(:table_name) { "some_schema.test_table" }
910
+ it { is_expected.to eq "test_table" }
911
+ end
912
+ context "with a mixed-case table name" do
913
+ let(:table_name) { "Test_Table" }
914
+ it { is_expected.to eq "test_table" }
915
+ end
916
+ end
917
+ context "with a schema name" do
918
+ let(:schema_name) { "test_schema" }
919
+ context "with a table name with no schema prefix" do
920
+ let(:table_name) { "test_table" }
921
+ it { is_expected.to eq "test_schema.test_table" }
922
+ end
923
+ context "with a table name with a schema prefix" do
924
+ let(:table_name) { "some_schema.test_table" }
925
+ it { is_expected.to eq "test_schema.test_table" }
926
+ end
927
+ end
928
+ context "with a mixed-case schema name" do
929
+ let(:schema_name) { "Test_Schema" }
930
+ context "with a table name with no schema prefix" do
931
+ let(:table_name) { "test_table" }
932
+ it { is_expected.to eq "test_schema.test_table" }
933
+ end
934
+ end
935
+ end
899
936
  end
900
937
 
901
938
  end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'flydata-core/wrapper_forwardable'
3
+
4
+ module FlydataCore
5
+
6
+ describe WrapperSingleForwardable do
7
+ class Target
8
+ def self.foo(a, b)
9
+ target_foo_result
10
+ end
11
+ end
12
+
13
+ class Test
14
+ extend WrapperSingleForwardable
15
+
16
+ def_wrapper_single_delegator Target, :foo
17
+
18
+ def initialize(item)
19
+ @item = item
20
+ end
21
+
22
+ def ==(other)
23
+ @item == other.item
24
+ end
25
+
26
+ attr_reader :item
27
+ end
28
+ let(:subject_object) { Test }
29
+ let(:args) { [ 'arg1', 'arg2' ] }
30
+
31
+ describe '.def_wrapper_single_delegator' do
32
+ it 'defines a class method of the given name to the subject class' do
33
+ expect(subject_object.respond_to?(:foo)).to eq true
34
+ end
35
+
36
+ describe 'the method defined by it' do
37
+ subject { subject_object.foo(*args) }
38
+ before do
39
+ expect(Target).to receive(:foo).with(*args).
40
+ and_return(target_foo_result)
41
+ end
42
+
43
+ context 'when the target method returns an object' do
44
+ let(:target_foo_result) { double('single_object') }
45
+
46
+ it 'returns an object of the subject class containing the target result' do
47
+ is_expected.to eq subject_object.new(target_foo_result)
48
+ end
49
+ end
50
+ context 'when the target method returns nil' do
51
+ let(:target_foo_result) { nil }
52
+
53
+ it 'returns nil' do
54
+ is_expected.to eq nil
55
+ end
56
+ end
57
+ context 'when the target method returns an array' do
58
+ let(:target_foo_result) { [ double('object1'), double('object2') ] }
59
+ it 'returns an array of instances of the subject class. Each instance contains an object returned from the target' do
60
+ is_expected.to eq target_foo_result.collect{|item| subject_object.new(item) }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ end
data/flydata.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: flydata 0.5.0 ruby lib
5
+ # stub: flydata 0.5.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "flydata"
9
- s.version = "0.5.0"
9
+ s.version = "0.5.1"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Koichi Fujikawa", "Masashi Miyazaki", "Matthew Luu", "Mak Inada", "Sriram NS"]
14
- s.date = "2015-07-24"
14
+ s.date = "2015-08-04"
15
15
  s.description = "FlyData Agent"
16
16
  s.email = "sysadmin@flydata.com"
17
17
  s.executables = ["fdmysqldump", "flydata", "serverinfo"]
@@ -51,8 +51,6 @@ Gem::Specification.new do |s|
51
51
  "flydata-core/lib/flydata-core/mysql/compatibility_checker.rb",
52
52
  "flydata-core/lib/flydata-core/option_validator.rb",
53
53
  "flydata-core/lib/flydata-core/query_job.rb",
54
- "flydata-core/lib/flydata-core/query_job/redshift.rb",
55
- "flydata-core/lib/flydata-core/query_job/table_status.rb",
56
54
  "flydata-core/lib/flydata-core/record/record.rb",
57
55
  "flydata-core/lib/flydata-core/redshift/string.rb",
58
56
  "flydata-core/lib/flydata-core/table_def.rb",
@@ -61,13 +59,13 @@ Gem::Specification.new do |s|
61
59
  "flydata-core/lib/flydata-core/table_def/redshift_table_def.rb",
62
60
  "flydata-core/lib/flydata-core/table_def/sync_redshift_table_def.rb",
63
61
  "flydata-core/lib/flydata-core/thread_context.rb",
62
+ "flydata-core/lib/flydata-core/wrapper_forwardable.rb",
64
63
  "flydata-core/spec/config/user_maintenance_spec.rb",
65
64
  "flydata-core/spec/fluent/config_helper_spec.rb",
66
65
  "flydata-core/spec/logger_spec.rb",
67
66
  "flydata-core/spec/mysql/command_generator_spec.rb",
68
67
  "flydata-core/spec/mysql/compatibility_checker.rb",
69
68
  "flydata-core/spec/option_validator_spec.rb",
70
- "flydata-core/spec/query_job/redshift_spec.rb",
71
69
  "flydata-core/spec/redshift/string_spec.rb",
72
70
  "flydata-core/spec/spec_helper.rb",
73
71
  "flydata-core/spec/table_def/autoload_redshift_table_def_spec.rb",
@@ -88,6 +86,7 @@ Gem::Specification.new do |s|
88
86
  "flydata-core/spec/table_def/mysqldump_test_unsigned.dump",
89
87
  "flydata-core/spec/table_def/redshift_table_def_spec.rb",
90
88
  "flydata-core/spec/table_def/sync_redshift_table_def_spec.rb",
89
+ "flydata-core/spec/wrapper_forwardable_spec.rb",
91
90
  "flydata.gemspec",
92
91
  "lib/fly_data_model.rb",
93
92
  "lib/flydata.rb",
@@ -243,7 +242,7 @@ Gem::Specification.new do |s|
243
242
  s.add_runtime_dependency(%q<treetop>, [">= 1.5.3", "~> 1.5"])
244
243
  s.add_runtime_dependency(%q<sys-filesystem>, [">= 1.1.3", "~> 1.1"])
245
244
  s.add_runtime_dependency(%q<io-console>, [">= 0.4.2", "~> 0.4.2"])
246
- s.add_runtime_dependency(%q<kodama>, [">= 0.1.6", "~> 0.1.2"])
245
+ s.add_runtime_dependency(%q<kodama>, [">= 0.1.7", "~> 0.1.2"])
247
246
  s.add_runtime_dependency(%q<serverengine>, ["~> 1.5"])
248
247
  s.add_development_dependency(%q<jeweler>, [">= 1.8.8", "~> 1.8"])
249
248
  s.add_development_dependency(%q<rspec>, ["~> 3.0"])
@@ -267,7 +266,7 @@ Gem::Specification.new do |s|
267
266
  s.add_dependency(%q<treetop>, [">= 1.5.3", "~> 1.5"])
268
267
  s.add_dependency(%q<sys-filesystem>, [">= 1.1.3", "~> 1.1"])
269
268
  s.add_dependency(%q<io-console>, [">= 0.4.2", "~> 0.4.2"])
270
- s.add_dependency(%q<kodama>, [">= 0.1.6", "~> 0.1.2"])
269
+ s.add_dependency(%q<kodama>, [">= 0.1.7", "~> 0.1.2"])
271
270
  s.add_dependency(%q<serverengine>, ["~> 1.5"])
272
271
  s.add_dependency(%q<jeweler>, [">= 1.8.8", "~> 1.8"])
273
272
  s.add_dependency(%q<rspec>, ["~> 3.0"])
@@ -292,7 +291,7 @@ Gem::Specification.new do |s|
292
291
  s.add_dependency(%q<treetop>, [">= 1.5.3", "~> 1.5"])
293
292
  s.add_dependency(%q<sys-filesystem>, [">= 1.1.3", "~> 1.1"])
294
293
  s.add_dependency(%q<io-console>, [">= 0.4.2", "~> 0.4.2"])
295
- s.add_dependency(%q<kodama>, [">= 0.1.6", "~> 0.1.2"])
294
+ s.add_dependency(%q<kodama>, [">= 0.1.7", "~> 0.1.2"])
296
295
  s.add_dependency(%q<serverengine>, ["~> 1.5"])
297
296
  s.add_dependency(%q<jeweler>, [">= 1.8.8", "~> 1.8"])
298
297
  s.add_dependency(%q<rspec>, ["~> 3.0"])
@@ -37,7 +37,7 @@ module Flydata
37
37
  # Start sender(fluentd) process
38
38
  log_info_stdout("Starting FlyData Agent sender process.") unless options[:quiet]
39
39
  raw_start(options)
40
-
40
+
41
41
  wait_until_client_ready(options)
42
42
  #wait_until_logs_uploaded
43
43
  fluentd_started = true
@@ -117,7 +117,7 @@ EOF
117
117
  `[ -f #{pid_file} ] && pgrep -P \`cat #{pid_file}\``.to_i > 0
118
118
  end
119
119
  def kill_all(options = {})
120
- if Kernel.system("ps ax | grep 'flydata' | grep -v grep | awk '{print \"kill \" $1}' | sh")
120
+ if Kernel.system("ps ax | grep 'flydata' | grep -v grep | grep fluentd | awk '{print \"kill \" $1}' | sh")
121
121
  log_info_stdout("Done.") unless options[:quiet]
122
122
  return true
123
123
  else
@@ -172,7 +172,7 @@ EOF
172
172
  raise "Somthing has gone wrong... Please try setup command again."
173
173
  end
174
174
  def wait_until_client_stop(options = {})
175
- retry_count = 5
175
+ retry_count = 10
176
176
  1.upto(retry_count) do |i|
177
177
  return true unless process_exist?
178
178
  log_info_stdout("Waiting for the client to stop... (#{i}/#{retry_count})") unless options[:quiet]
@@ -57,6 +57,23 @@ class MysqlBinlogFlydataInput < MysqlBinlogInput
57
57
  config_param :idle_timeout, :time, :default => 1800 # 30 min
58
58
  config_param :check_interval, :integer, :default => 5 # 5 sec
59
59
  config_param :ssl_ca_content, :string, :default => ''
60
+ config_param :ssl_cipher, :string, :default => nil
61
+
62
+ # Secondary ssl cipher is for a workaround to handle 'dh key too small' error
63
+ # If mysql-server is v5.6.25 or older, and client openssl is
64
+ # 1.0.1f-1ubuntu-2.15(for ubuntu) or later, client will get the above error because.
65
+ # the key length returned from mysql-server is only 512 bits.
66
+ #
67
+ # In case of dh key error, we retry with non-DH cipher.
68
+ #
69
+ # * SECURITY IMPROVEMENT: reject dh keys smaller than 768 bits
70
+ # https://launchpad.net/ubuntu/+source/openssl/1.0.1f-1ubuntu2.15
71
+ #
72
+ # Supported ssl cipher list for mysql(openssl)
73
+ # https://dev.mysql.com/doc/refman/5.6/en/ssl-options.html
74
+
75
+ NON_DH_SSL_CIPHER = "AES256-GCM-SHA384:AES256-SHA:AES256-SHA256:CAMELLIA256-SHA:DES-CBC3-SHA:PSK-3DES-EDE-CBC-SHA:PSK-AES256-CBC-SHA:SRP-DSS-3DES-EDE-CBC-SHA:SRP-DSS-AES-128-CBC-SHA:SRP-DSS-AES-256-CBC-SHA:SRP-RSA-3DES-EDE-CBC-SHA:SRP-RSA-AES-128-CBC-S:SRP-RSA-AES-256-CBC-SHA"
76
+ config_param :secondary_ssl_cipher, :string, :default => NON_DH_SSL_CIPHER
60
77
 
61
78
  def configure(conf)
62
79
  super
@@ -110,7 +127,6 @@ class MysqlBinlogFlydataInput < MysqlBinlogInput
110
127
  h
111
128
  end
112
129
 
113
-
114
130
  # Set context
115
131
  @context = Mysql::Context.new(
116
132
  database: @database, tables: @tables,
@@ -162,29 +178,48 @@ EOS
162
178
  @context) do |event|
163
179
  @record_dispatcher.dispatch(event)
164
180
  end
165
- start_kodama(mysql_url) do |c|
166
- c.binlog_position_file = @position_file
167
- if @ssl_ca_path.to_s != '' && c.respond_to?(:ssl_ca=)
168
- $log.info "SSL is enabled. (ssl_ca: #{@ssl_ca_path})"
169
- c.ssl_ca = @ssl_ca_path
170
- end
171
181
 
172
- if c.respond_to?(:sent_binlog_position_file=)
173
- $log.info "Sent position feature is enabled. sent_position_file:#{@sent_position_file_path}"
174
- c.sent_binlog_position_file = @sent_position_file_path
175
- end
182
+ current_ssl_cipher = @ssl_cipher
183
+ retried = false
184
+ begin
185
+ start_kodama(mysql_url) do |c|
186
+ c.binlog_position_file = @position_file
187
+ if @ssl_ca_path.to_s != '' && c.respond_to?(:ssl_ca=)
188
+ $log.info "SSL is enabled. (ssl_ca: #{@ssl_ca_path})"
189
+ c.ssl_ca = @ssl_ca_path
190
+ unless current_ssl_cipher.to_s.empty?
191
+ $log.info "SSL cipher is set. (ssl_cipher: #{current_ssl_cipher})"
192
+ c.ssl_cipher = current_ssl_cipher
193
+ end
194
+ end
176
195
 
177
- $log.info("Binlog position - resume_pos:'#{IO.read(@position_file) rescue IOError}' " +
178
- "sent_pos:'#{IO.read(@sent_position_file_path) rescue IOError}'")
196
+ if c.respond_to?(:sent_binlog_position_file=)
197
+ $log.info "Sent position feature is enabled. sent_position_file:#{@sent_position_file_path}"
198
+ c.sent_binlog_position_file = @sent_position_file_path
199
+ end
179
200
 
180
- c.connection_retry_limit = @retry_limit
181
- c.connection_retry_wait = @retry_wait
182
- c.log_level = @log_level.to_sym
183
- @listen_events.each do |event_type|
184
- $log.trace { "registered binlog event listener '#{event_type}'" }
185
- c.send("on_#{event_type}", &method(:event_listener))
201
+ $log.info("Binlog position - resume_pos:'#{IO.read(@position_file) rescue IOError}' " +
202
+ "sent_pos:'#{IO.read(@sent_position_file_path) rescue IOError}'")
203
+
204
+ c.connection_retry_limit = @retry_limit
205
+ c.connection_retry_wait = @retry_wait
206
+ c.log_level = @log_level.to_sym
207
+ @listen_events.each do |event_type|
208
+ $log.trace { "registered binlog event listener '#{event_type}'" }
209
+ c.send("on_#{event_type}", &method(:event_listener))
210
+ end
211
+ end
212
+ rescue Binlog::Error => e
213
+ if /dh key too small/.match(e.to_s) && !retried && !@secondary_ssl_cipher.to_s.empty?
214
+ retried = true
215
+ current_ssl_cipher = @secondary_ssl_cipher
216
+ $log.warn("Retry with secondary ssl cipher list due to '#{e}' - secondary_ssl_cipher: '#{@secondary_ssl_cipher}'")
217
+ retry
218
+ else
219
+ raise e
186
220
  end
187
221
  end
222
+
188
223
  rescue => e
189
224
  # HACK: mysql-replication-listener has a network connection leak bug which doesn't release a connection
190
225
  # to MySQL. Rather than fixing the bug, restarting the fluentd process for now.
@@ -894,7 +894,7 @@ grammar MysqlAlterTable
894
894
  }
895
895
  end
896
896
  rule character_set_opt
897
- 'character set'i sp value {
897
+ charset sp value {
898
898
  def character_set_opt_option
899
899
  { cs: FlydataCore::TableDef::MysqlTableDef.flydata_charset(value.raw_value) }
900
900
  end
@@ -185,19 +185,50 @@ describe 'MysqlAlterTableParser' do
185
185
  end
186
186
 
187
187
  context 'with after option' do
188
- let(:query) { "alter table test_table add column value varchar(26) after id" }
189
- it do
190
- expect(subject).to eq({
191
- type: :alter_table,
192
- table_name: "test_table",
193
- actions: [{
194
- action: :add_column,
195
- column: "value",
196
- type: "varchar(78)",
197
- after: 'id',
198
- query: "add column value varchar(26) after id"
199
- }]
200
- })
188
+ context 'without charset' do
189
+ let(:query) { "alter table test_table add column value varchar(26) after id" }
190
+ it do
191
+ expect(subject).to eq({
192
+ type: :alter_table,
193
+ table_name: "test_table",
194
+ actions: [{
195
+ action: :add_column,
196
+ column: "value",
197
+ type: "varchar(78)",
198
+ after: 'id',
199
+ query: "add column value varchar(26) after id"
200
+ }]
201
+ })
202
+ end
203
+ end
204
+ context 'with charset and collate' do
205
+ shared_examples "parse character set correctly" do
206
+ let(:query) { "alter table `kiikplan`.`plan` add column `email_header` varchar(1024) #{charset} utf8 COLLATE utf8_general_ci NULL after `color`" }
207
+ it do
208
+ expect(subject).to eq({
209
+ type: :alter_table,
210
+ table_name: "plan",
211
+ actions: [{
212
+ action: :add_column,
213
+ column: "email_header",
214
+ type: "varchar(3072)",
215
+ cs: "UTF_8",
216
+ after: 'color',
217
+ query: "add column `email_header` varchar(1024) #{charset} utf8 COLLATE utf8_general_ci NULL after `color`"
218
+ }],
219
+ schema_name: "kiikplan"
220
+ })
221
+ end
222
+ end
223
+ context "with character set" do
224
+ let(:charset) { "character set" }
225
+ include_examples "parse character set correctly"
226
+ end
227
+
228
+ context "with charset" do
229
+ let(:charset) { "CHARSET" }
230
+ include_examples "parse character set correctly"
231
+ end
201
232
  end
202
233
  end
203
234
  shared_examples "generating a flydata record for the given query" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flydata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Fujikawa
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-07-24 00:00:00.000000000 Z
15
+ date: 2015-08-04 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rest-client
@@ -248,7 +248,7 @@ dependencies:
248
248
  requirements:
249
249
  - - '>='
250
250
  - !ruby/object:Gem::Version
251
- version: 0.1.6
251
+ version: 0.1.7
252
252
  - - ~>
253
253
  - !ruby/object:Gem::Version
254
254
  version: 0.1.2
@@ -258,7 +258,7 @@ dependencies:
258
258
  requirements:
259
259
  - - '>='
260
260
  - !ruby/object:Gem::Version
261
- version: 0.1.6
261
+ version: 0.1.7
262
262
  - - ~>
263
263
  - !ruby/object:Gem::Version
264
264
  version: 0.1.2
@@ -488,8 +488,6 @@ files:
488
488
  - flydata-core/lib/flydata-core/mysql/compatibility_checker.rb
489
489
  - flydata-core/lib/flydata-core/option_validator.rb
490
490
  - flydata-core/lib/flydata-core/query_job.rb
491
- - flydata-core/lib/flydata-core/query_job/redshift.rb
492
- - flydata-core/lib/flydata-core/query_job/table_status.rb
493
491
  - flydata-core/lib/flydata-core/record/record.rb
494
492
  - flydata-core/lib/flydata-core/redshift/string.rb
495
493
  - flydata-core/lib/flydata-core/table_def.rb
@@ -498,13 +496,13 @@ files:
498
496
  - flydata-core/lib/flydata-core/table_def/redshift_table_def.rb
499
497
  - flydata-core/lib/flydata-core/table_def/sync_redshift_table_def.rb
500
498
  - flydata-core/lib/flydata-core/thread_context.rb
499
+ - flydata-core/lib/flydata-core/wrapper_forwardable.rb
501
500
  - flydata-core/spec/config/user_maintenance_spec.rb
502
501
  - flydata-core/spec/fluent/config_helper_spec.rb
503
502
  - flydata-core/spec/logger_spec.rb
504
503
  - flydata-core/spec/mysql/command_generator_spec.rb
505
504
  - flydata-core/spec/mysql/compatibility_checker.rb
506
505
  - flydata-core/spec/option_validator_spec.rb
507
- - flydata-core/spec/query_job/redshift_spec.rb
508
506
  - flydata-core/spec/redshift/string_spec.rb
509
507
  - flydata-core/spec/spec_helper.rb
510
508
  - flydata-core/spec/table_def/autoload_redshift_table_def_spec.rb
@@ -525,6 +523,7 @@ files:
525
523
  - flydata-core/spec/table_def/mysqldump_test_unsigned.dump
526
524
  - flydata-core/spec/table_def/redshift_table_def_spec.rb
527
525
  - flydata-core/spec/table_def/sync_redshift_table_def_spec.rb
526
+ - flydata-core/spec/wrapper_forwardable_spec.rb
528
527
  - flydata.gemspec
529
528
  - lib/fly_data_model.rb
530
529
  - lib/flydata.rb
@@ -1,27 +0,0 @@
1
- require 'flydata-core/table_def/redshift_table_def'
2
-
3
- module FlydataCore
4
- module QueryJob
5
-
6
- class Redshift
7
- # returns a list of table names used in the Query Job system.
8
- def self.target_table_names(flydata_table_names)
9
- flydata_table_names = [ flydata_table_names ] unless flydata_table_names.kind_of?(Array)
10
-
11
- flydata_table_names.collect {|flydata_table_name|
12
- redshift_table_name = TableDef::RedshiftTableDef.convert_to_valid_table_name(flydata_table_name)
13
- table_names = [ redshift_table_name ]
14
- if redshift_table_name != flydata_table_name
15
- # for backward compatibility
16
- # Old implementation used FlyData table names. To support it, the
17
- # method adds the flydata_table_name as well.
18
- table_names << flydata_table_name
19
- end
20
-
21
- table_names
22
- }.flatten
23
- end
24
- end
25
-
26
- end
27
- end
@@ -1,44 +0,0 @@
1
- require 'flydata-core/query_job/redshift'
2
- require 'flydata-core/table_def/redshift_table_def'
3
-
4
- module FlydataCore
5
- module QueryJob
6
-
7
- class TableStatus
8
- @@domain = 'flydata_redshift_table_status'
9
-
10
- def self.domain=(domain)
11
- @@domain = domain
12
- end
13
-
14
- def self.sdb=(sdb)
15
- @@sdb = sdb
16
- end
17
-
18
- def self.where(*args)
19
- table_status_items = {}
20
- @@sdb.domains[@@domain].items.where(*args).each(select: :all) do |item|
21
- class << item
22
- # returns the corect (Redshift) table name
23
- def table_name
24
- FlydataCore::TableDef::RedshiftTableDef.convert_to_valid_table_name(attributes['table_name'].first)
25
- end
26
-
27
- def target_table_names
28
- FlydataCore::QueryJob::Redshift.target_table_names(attributes['table_name'].first)
29
- end
30
- end
31
- tn = item.attributes['table_name'].first
32
- redshift_table_name = FlydataCore::TableDef::RedshiftTableDef.convert_to_valid_table_name(tn)
33
- if redshift_table_name == tn
34
- table_status_items[redshift_table_name] ||= item
35
- else
36
- table_status_items[redshift_table_name] = item
37
- end
38
- end
39
- table_status_items.values
40
- end
41
- end
42
-
43
- end
44
- end
@@ -1,34 +0,0 @@
1
- require 'spec_helper'
2
- require 'flydata-core/query_job/redshift'
3
-
4
- module FlydataCore::QueryJob
5
-
6
- describe Redshift do
7
- describe '.target_table_names' do
8
- subject { described_class.target_table_names(flydata_table_names) }
9
-
10
- context 'with a single table name' do
11
- let(:flydata_table_names) { "my_table" }
12
-
13
- it { is_expected.to eq [ flydata_table_names ] }
14
- end
15
-
16
- context 'with multiples table names' do
17
- let(:flydata_table_names) { %w(my_table1 my_table2) }
18
-
19
- it { is_expected.to eq flydata_table_names }
20
- end
21
- context 'with a mixed case table name' do
22
- let(:flydata_table_names) { "MyTable" }
23
-
24
- it { is_expected.to eq [ flydata_table_names.downcase, flydata_table_names ] }
25
- end
26
- context 'with table names including mixed case one' do
27
- let(:flydata_table_names) { %w(MyTable my_table2) }
28
-
29
- it { is_expected.to eq %w(mytable MyTable my_table2) }
30
- end
31
- end
32
- end
33
-
34
- end