flydata 0.5.2 → 0.5.3
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 +4 -4
- data/VERSION +1 -1
- data/circle.yml +2 -1
- data/flydata-core/lib/flydata-core/mysql/compatibility_checker.rb +110 -52
- data/flydata-core/spec/mysql/compatibility_checker_spec.rb +361 -0
- data/flydata.gemspec +5 -4
- data/lib/flydata/compatibility_check.rb +6 -1
- data/test-suite.sh +56 -0
- metadata +4 -3
- data/flydata-core/spec/mysql/compatibility_checker.rb +0 -186
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 550d6891d0b0315d762ded08f079e915888c9b52
|
4
|
+
data.tar.gz: 477cbc3a4977c15b17b9dd3a7ecedfa3fe35595d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9eaccb595b37a199a92244e2e27d6b8c8cf79740a8dd69a9add01cce9a68bcd1f94428c2749fdf28d35784d03ff5c0f02c13ccd6d71b324d8b129d93a9f46c5
|
7
|
+
data.tar.gz: bcfa91ee81945016d24f1f686cb329f7c940ab5c36db7baad3886de2fbd34f12d5be6eae80811fccc74aa0f4a2dd31477be98f96045717e486a399d33c86e8e4
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.3
|
data/circle.yml
CHANGED
@@ -6,6 +6,7 @@ dependencies:
|
|
6
6
|
pre:
|
7
7
|
- sudo dpkg -l |grep libboost|grep 1.48|awk '{print $2}'|xargs sudo apt-get purge -y
|
8
8
|
- sudo apt-get autoremove
|
9
|
+
- sudo apt-get update
|
9
10
|
- sudo apt-get install -y libboost-system1.54.0
|
10
11
|
- sudo apt-get install -y libboost-system1.54-dev
|
11
12
|
- sudo apt-get install -y libboost-thread1.54.0
|
@@ -21,4 +22,4 @@ database:
|
|
21
22
|
|
22
23
|
test:
|
23
24
|
override:
|
24
|
-
-
|
25
|
+
- ./test-suite.sh
|
@@ -5,6 +5,10 @@ module FlydataCore
|
|
5
5
|
module Mysql
|
6
6
|
class CompatibilityChecker
|
7
7
|
def initialize(option = {})
|
8
|
+
if option && option.has_key?(:host) && option[:host] == 'localhost'
|
9
|
+
option = option.dup
|
10
|
+
option[:host] = '127.0.0.1' # avoid socket access which Agent never uses
|
11
|
+
end
|
8
12
|
@option = option || {}
|
9
13
|
end
|
10
14
|
|
@@ -113,62 +117,113 @@ module FlydataCore
|
|
113
117
|
class BinlogParameterChecker < MysqlCompatibilityChecker
|
114
118
|
include MysqlVariablesHandling
|
115
119
|
|
116
|
-
|
120
|
+
|
121
|
+
BASE_SYS_VAR_TO_CHECK = {
|
117
122
|
# parameter => expected value
|
118
|
-
'binlog_format'=>'ROW',
|
119
|
-
'binlog_checksum'=>'NONE',
|
120
|
-
'log_bin_use_v1_row_events'=>'ON',
|
121
|
-
'log_slave_updates'=>'ON',
|
123
|
+
'binlog_format' => 'ROW',
|
124
|
+
#'binlog_checksum' => 'NONE', # no longer necessary with mysql-replication-listener 0.2.0
|
125
|
+
'log_bin_use_v1_row_events' => 'ON',
|
126
|
+
'log_slave_updates' => 'ON',
|
127
|
+
}
|
128
|
+
|
129
|
+
ADDITIONAL_SYS_VAR_TO_CHECK = {
|
122
130
|
# parameter => {"comparison sign"=>minimum value}
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
#'wait_timeout'=>{'>'=>60}
|
131
|
+
'net_read_timeout'=>{'>='=>600},
|
132
|
+
'net_write_timeout'=>{'>='=>600},
|
133
|
+
'wait_timeout'=>{'>='=>60},
|
127
134
|
}
|
128
|
-
|
135
|
+
|
136
|
+
SYS_VAR_TO_CHECK = BASE_SYS_VAR_TO_CHECK.merge(ADDITIONAL_SYS_VAR_TO_CHECK)
|
129
137
|
|
130
138
|
def check_result(result, option = @option)
|
131
|
-
errors = {}
|
132
139
|
param_hash = convert_result_to_hash(result)
|
133
|
-
|
134
|
-
compare_sys_var_values(param_hash, SYS_VAR_TO_CHECK, errors, OPTIONAL_SYS_VAR)
|
140
|
+
errors = compare_sys_var_values(param_hash, self.class::SYS_VAR_TO_CHECK)
|
135
141
|
|
136
142
|
unless errors.empty?
|
137
|
-
|
138
|
-
errors.each_key do |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
|
144
|
-
end
|
145
|
-
raise FlydataCore::MysqlCompatibilityError,
|
146
|
-
"These system variable(s) are not the correct value: #{error_explanation}\n" +
|
147
|
-
" Please change these system variables for FlyData Sync to run"
|
143
|
+
raise FlydataCore::MysqlCompatibilityError, build_error_message(errors)
|
148
144
|
end
|
149
145
|
end
|
150
146
|
|
147
|
+
def build_error_message(errors)
|
148
|
+
err_msg = errors.inject('') {|m, (k, v)| m << "\n * #{v[:err_reason]}"}
|
149
|
+
"These system variable(s) are not the correct value: #{err_msg}\n" +
|
150
|
+
" Please change these system variables for FlyData Sync to run"
|
151
|
+
end
|
152
|
+
|
151
153
|
private
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
154
|
+
|
155
|
+
def compare_sys_var_values(input_value_hash, expected_value_hash)
|
156
|
+
# { '<param-name>' => {actual_val: '<actual-val>', err_reason: '<err-reason>'} }
|
157
|
+
errors = {}
|
158
|
+
|
159
|
+
expected_value_hash.each do |param_name, exp_val_info|
|
160
|
+
# Ignore parameters if not returned
|
161
|
+
# binlog_checksum and log_bin_use_v1_row_events are supported only for Mysql v5.6
|
162
|
+
next unless input_value_hash.has_key?(param_name)
|
163
|
+
actual_val = input_value_hash[param_name]
|
164
|
+
err_reason = nil
|
165
|
+
|
166
|
+
if exp_val_info.kind_of?(Hash)
|
167
|
+
exp_val_info.each do |compare_sym, exp_val|
|
168
|
+
case compare_sym
|
169
|
+
when '='
|
170
|
+
unless actual_val.to_s != exp_val.to_s
|
171
|
+
err_reason = "#{param_name} is '#{actual_val}' but should be '#{exp_val}'"
|
172
|
+
end
|
173
|
+
when '>='
|
174
|
+
unless actual_val.to_i >= exp_val.to_i
|
175
|
+
err_reason = "#{param_name} is '#{actual_val}' but should be at least '#{exp_val}'"
|
176
|
+
end
|
177
|
+
else
|
178
|
+
raise "Unsupported compare symbol - #{compare_sym}"
|
167
179
|
end
|
180
|
+
break # support just one key-value for now
|
168
181
|
end
|
169
|
-
elsif
|
170
|
-
|
182
|
+
elsif exp_val_info.to_s != actual_val.to_s
|
183
|
+
err_reason = "#{param_name} is '#{actual_val}' but should be '#{exp_val_info}'"
|
171
184
|
end
|
185
|
+
errors[param_name] = {actual_val: actual_val, err_reason: err_reason} if err_reason
|
186
|
+
end
|
187
|
+
errors
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class RequiredBinlogParameterChecker < BinlogParameterChecker
|
192
|
+
SYS_VAR_TO_CHECK = BASE_SYS_VAR_TO_CHECK
|
193
|
+
end
|
194
|
+
|
195
|
+
class OptionalBinlogParameterChecker < BinlogParameterChecker
|
196
|
+
SYS_VAR_TO_CHECK = ADDITIONAL_SYS_VAR_TO_CHECK
|
197
|
+
|
198
|
+
def build_error_message(errors)
|
199
|
+
err_msg = errors.inject('') {|m, (k, v)| m << "\n * #{v[:err_reason]}"}
|
200
|
+
"[WARNING] These system variable(s) are not the recommended values: #{err_msg}\n" +
|
201
|
+
" These settings are not required but highly recommended for the FlyData Agent to run as efficiently as possible"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class TableExistenceChecker < MysqlCompatibilityChecker
|
206
|
+
TABLE_EXISTENCE_CHECK_QUERY_TMPLT = <<EOT
|
207
|
+
SELECT
|
208
|
+
t.table_name as table_name
|
209
|
+
FROM
|
210
|
+
information_schema.tables t
|
211
|
+
WHERE
|
212
|
+
t.table_schema='%{database}'
|
213
|
+
AND t.table_name in (%{table_names});
|
214
|
+
EOT
|
215
|
+
def create_query(option = @option)
|
216
|
+
TABLE_EXISTENCE_CHECK_QUERY_TMPLT % {database: option[:database], table_names: option[:tables].collect{|tn| "'#{tn}'"}.join(',')}
|
217
|
+
end
|
218
|
+
|
219
|
+
def check_result(result, option = @option)
|
220
|
+
existing_tables = []
|
221
|
+
result.each {|r| existing_tables << r['table_name']}
|
222
|
+
missing_tables = option[:tables] - existing_tables
|
223
|
+
|
224
|
+
unless missing_tables.empty?
|
225
|
+
raise FlydataCore::MysqlCompatibilityError,
|
226
|
+
"These tables are missing. Create these tables on your database or remove them from the data entry : #{missing_tables.join(", ")}"
|
172
227
|
end
|
173
228
|
end
|
174
229
|
end
|
@@ -206,23 +261,26 @@ module FlydataCore
|
|
206
261
|
|
207
262
|
class PrimaryKeyChecker < MysqlCompatibilityChecker
|
208
263
|
PK_CHECK_QUERY_TMPLT = <<EOT
|
209
|
-
SELECT
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
264
|
+
SELECT
|
265
|
+
c.table_name as table_name,
|
266
|
+
SUM(IF(c.column_key = 'PRI', 1, 0)) as num_pk
|
267
|
+
FROM
|
268
|
+
information_schema.columns c
|
269
|
+
WHERE
|
270
|
+
c.table_schema='%{database}'
|
271
|
+
AND c.table_name in (%{table_names})
|
272
|
+
GROUP BY
|
273
|
+
c.table_name
|
274
|
+
HAVING
|
275
|
+
num_pk = 0;
|
217
276
|
EOT
|
218
277
|
def create_query(option = @option)
|
219
278
|
PK_CHECK_QUERY_TMPLT % {database: option[:database], table_names: option[:tables].collect{|tn| "'#{tn}'"}.join(',')}
|
220
279
|
end
|
221
280
|
|
222
281
|
def check_result(result, option = @option)
|
223
|
-
|
224
|
-
result.each {|r|
|
225
|
-
missing_pk_tables = option[:tables] - pk_tables
|
282
|
+
missing_pk_tables = []
|
283
|
+
result.each {|r| missing_pk_tables << r['table_name']}
|
226
284
|
|
227
285
|
unless missing_pk_tables.empty?
|
228
286
|
raise FlydataCore::MysqlCompatibilityError,
|
@@ -0,0 +1,361 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'flydata-core/mysql/compatibility_checker'
|
3
|
+
|
4
|
+
module FlydataCore
|
5
|
+
module Mysql
|
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
|
12
|
+
|
13
|
+
describe TableExistenceChecker 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
|
20
|
+
t.table_name as table_name
|
21
|
+
FROM
|
22
|
+
information_schema.tables t
|
23
|
+
WHERE
|
24
|
+
t.table_schema='test_db'
|
25
|
+
AND t.table_name in ('table_1','table_2','table_3');
|
26
|
+
EOT
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#check_reesult' do
|
31
|
+
let(:result) { [] }
|
32
|
+
subject { subject_object.check_result(result) }
|
33
|
+
|
34
|
+
context 'when all tables exist' do
|
35
|
+
let(:result) do
|
36
|
+
[ {'table_name' => 'table_1'},
|
37
|
+
{'table_name' => 'table_2'},
|
38
|
+
{'table_name' => 'table_3'}, ]
|
39
|
+
end
|
40
|
+
it { expect{subject}.not_to raise_error }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when some tables does not exist' do
|
44
|
+
let(:result) do
|
45
|
+
[{"table_name" => "table_2"}]
|
46
|
+
end
|
47
|
+
it do
|
48
|
+
expect{subject}.to raise_error {|e|
|
49
|
+
expect(e).to be_kind_of(FlydataCore::MysqlCompatibilityError)
|
50
|
+
expect(e.to_s.include?("table_1")).to be_truthy
|
51
|
+
expect(e.to_s.include?("table_2")).to be_falsey
|
52
|
+
expect(e.to_s.include?("table_3")).to be_truthy
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe PrimaryKeyChecker do
|
60
|
+
let(:subject_object) { described_class.new(option) }
|
61
|
+
|
62
|
+
describe '#create_query' do
|
63
|
+
subject { subject_object.create_query }
|
64
|
+
it { is_expected.to eq <<EOT
|
65
|
+
SELECT
|
66
|
+
c.table_name as table_name,
|
67
|
+
SUM(IF(c.column_key = 'PRI', 1, 0)) as num_pk
|
68
|
+
FROM
|
69
|
+
information_schema.columns c
|
70
|
+
WHERE
|
71
|
+
c.table_schema='test_db'
|
72
|
+
AND c.table_name in ('table_1','table_2','table_3')
|
73
|
+
GROUP BY
|
74
|
+
c.table_name
|
75
|
+
HAVING
|
76
|
+
num_pk = 0;
|
77
|
+
EOT
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#check_reesult' do
|
82
|
+
let(:result) { [] }
|
83
|
+
subject { subject_object.check_result(result) }
|
84
|
+
|
85
|
+
context 'when all tables have pk' do
|
86
|
+
let(:result) do
|
87
|
+
[]
|
88
|
+
end
|
89
|
+
it { expect{subject}.not_to raise_error }
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when some tables does not have pk' do
|
93
|
+
let(:result) do
|
94
|
+
[{"table_name" => "table_1"}, {"table_name" => "table_3"}]
|
95
|
+
end
|
96
|
+
it do
|
97
|
+
expect{subject}.to raise_error {|e|
|
98
|
+
expect(e).to be_kind_of(FlydataCore::MysqlCompatibilityError)
|
99
|
+
expect(e.to_s.include?("table_1")).to be_truthy
|
100
|
+
expect(e.to_s.include?("table_2")).to be_falsey
|
101
|
+
expect(e.to_s.include?("table_3")).to be_truthy
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe BinlogParameterChecker do
|
110
|
+
let(:subject_object) { described_class.new({}) }
|
111
|
+
|
112
|
+
describe "#check_result" do
|
113
|
+
let(:sys_var) do
|
114
|
+
[
|
115
|
+
{'Variable_name'=>'binlog_format','Value'=>'ROW'},
|
116
|
+
{'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
|
117
|
+
{'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
|
118
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'ON'},
|
119
|
+
{'Variable_name'=>'net_read_timeout','Value'=>600},
|
120
|
+
{'Variable_name'=>'net_write_timeout','Value'=>600},
|
121
|
+
{'Variable_name'=>'wait_timeout','Value'=>60}
|
122
|
+
]
|
123
|
+
end
|
124
|
+
subject { subject_object.check_result(sys_var, {}) }
|
125
|
+
|
126
|
+
context "where parameters are valid" do
|
127
|
+
it do
|
128
|
+
expect{subject}.to_not raise_error
|
129
|
+
end
|
130
|
+
end
|
131
|
+
context "where parameters are invalid" do
|
132
|
+
let(:sys_var) do
|
133
|
+
[
|
134
|
+
{'Variable_name'=>'binlog_format','Value'=>'MIXED'},
|
135
|
+
{'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
|
136
|
+
{'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
|
137
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'ON'},
|
138
|
+
{'Variable_name'=>'net_read_timeout','Value'=>600},
|
139
|
+
{'Variable_name'=>'net_write_timeout','Value'=>600},
|
140
|
+
{'Variable_name'=>'wait_timeout','Value'=>30}
|
141
|
+
]
|
142
|
+
end
|
143
|
+
it do
|
144
|
+
expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError, /binlog_format.*\n.*wait_timeout/)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "where parameters are not returned" do
|
149
|
+
let(:sys_var) do
|
150
|
+
[
|
151
|
+
{'Variable_name'=>'binlog_format','Value'=>'ROW'},
|
152
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'ON'},
|
153
|
+
{'Variable_name'=>'net_read_timeout','Value'=>600},
|
154
|
+
{'Variable_name'=>'net_write_timeout','Value'=>600},
|
155
|
+
{'Variable_name'=>'wait_timeout','Value'=>60},
|
156
|
+
]
|
157
|
+
end
|
158
|
+
it 'ignores missing parameters' do
|
159
|
+
expect{subject}.not_to raise_error
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
describe "#compare_sys_var_values" do
|
164
|
+
let(:input_val) { nil }
|
165
|
+
let(:expected_val) do
|
166
|
+
{
|
167
|
+
'value_1' => 'foo',
|
168
|
+
'value_2' => 50,
|
169
|
+
'value_3' => {">="=>100}
|
170
|
+
}
|
171
|
+
end
|
172
|
+
let(:errors) { {} }
|
173
|
+
|
174
|
+
subject { subject_object.send(:compare_sys_var_values, input_val, expected_val) }
|
175
|
+
|
176
|
+
shared_examples "expect correct errors from values" do
|
177
|
+
it { is_expected.to eq(expecting_errors) }
|
178
|
+
end
|
179
|
+
|
180
|
+
context "when getting valid parameters" do
|
181
|
+
let(:input_val) do
|
182
|
+
{
|
183
|
+
'value_1' => 'foo',
|
184
|
+
'value_2' => 50,
|
185
|
+
'value_3' => 200
|
186
|
+
}
|
187
|
+
end
|
188
|
+
let(:expecting_errors) { {} }
|
189
|
+
it_behaves_like "expect correct errors from values"
|
190
|
+
end
|
191
|
+
context "when getting one invalid exact parameters for int" do
|
192
|
+
let(:input_val) do
|
193
|
+
{
|
194
|
+
'value_1' => 'foo',
|
195
|
+
'value_2' => 20,
|
196
|
+
'value_3' => 100
|
197
|
+
}
|
198
|
+
end
|
199
|
+
let(:expecting_errors) do
|
200
|
+
{
|
201
|
+
'value_2' => { actual_val: 20, err_reason: "value_2 is '20' but should be '50'" }
|
202
|
+
}
|
203
|
+
end
|
204
|
+
it_behaves_like "expect correct errors from values"
|
205
|
+
end
|
206
|
+
context "when getting one invalid exact parameter for string" do
|
207
|
+
let(:input_val) do
|
208
|
+
{
|
209
|
+
'value_1' => 'fo',
|
210
|
+
'value_2' => 50,
|
211
|
+
'value_3' => 100
|
212
|
+
}
|
213
|
+
end
|
214
|
+
let(:expecting_errors) do
|
215
|
+
{
|
216
|
+
'value_1' => { actual_val: 'fo', err_reason: "value_1 is 'fo' but should be 'foo'" }
|
217
|
+
}
|
218
|
+
end
|
219
|
+
it_behaves_like "expect correct errors from values"
|
220
|
+
end
|
221
|
+
context "when getting one invalid comparitive parameter that's lower than required" do
|
222
|
+
let(:input_val) do
|
223
|
+
{
|
224
|
+
'value_1' => 'foo',
|
225
|
+
'value_2' => 50,
|
226
|
+
'value_3' => 1
|
227
|
+
}
|
228
|
+
end
|
229
|
+
let(:expecting_errors) do
|
230
|
+
{
|
231
|
+
'value_3' => { actual_val: 1, err_reason: "value_3 is '1' but should be at least '100'" }
|
232
|
+
}
|
233
|
+
end
|
234
|
+
it_behaves_like "expect correct errors from values"
|
235
|
+
end
|
236
|
+
context "when getting a valid comparitive parameter that's higher than required" do
|
237
|
+
let(:input_val) do
|
238
|
+
{
|
239
|
+
'value_1' => 'foo',
|
240
|
+
'value_2' => 50,
|
241
|
+
'value_3' => 101
|
242
|
+
}
|
243
|
+
end
|
244
|
+
let(:expecting_errors) { {} }
|
245
|
+
it_behaves_like "expect correct errors from values"
|
246
|
+
end
|
247
|
+
context "when getting muliple invalid parameters" do
|
248
|
+
let(:input_val) do
|
249
|
+
{
|
250
|
+
'value_1' => 'fo',
|
251
|
+
'value_2' => 50,
|
252
|
+
'value_3' => 15
|
253
|
+
}
|
254
|
+
end
|
255
|
+
let(:expecting_errors) { {value_1:'fo', value_3:15} }
|
256
|
+
let(:expecting_errors) do
|
257
|
+
{
|
258
|
+
'value_1' => { actual_val: 'fo', err_reason: "value_1 is 'fo' but should be 'foo'" },
|
259
|
+
'value_3' => { actual_val: 15, err_reason: "value_3 is '15' but should be at least '100'" },
|
260
|
+
}
|
261
|
+
end
|
262
|
+
it_behaves_like "expect correct errors from values"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe RequiredBinlogParameterChecker do
|
268
|
+
let(:subject_object) { described_class.new({}) }
|
269
|
+
|
270
|
+
describe "#check_result" do
|
271
|
+
let(:sys_var) do
|
272
|
+
[
|
273
|
+
{'Variable_name'=>'binlog_format','Value'=>'ROW'},
|
274
|
+
{'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
|
275
|
+
{'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
|
276
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'ON'},
|
277
|
+
]
|
278
|
+
end
|
279
|
+
subject { subject_object.check_result(sys_var) }
|
280
|
+
|
281
|
+
context 'where parameters are valid' do
|
282
|
+
it { expect{subject}.not_to raise_error }
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'where parameters contain optional paramters' do
|
286
|
+
let(:sys_var) do
|
287
|
+
[
|
288
|
+
{'Variable_name'=>'binlog_format','Value'=>'ROW'},
|
289
|
+
{'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
|
290
|
+
{'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
|
291
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'ON'},
|
292
|
+
{'Variable_name'=>'net_read_timeout','Value'=>1},
|
293
|
+
{'Variable_name'=>'net_write_timeout','Value'=>1},
|
294
|
+
{'Variable_name'=>'wait_timeout','Value'=>1}
|
295
|
+
]
|
296
|
+
end
|
297
|
+
it { expect{subject}.not_to raise_error }
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'where parameters contain invalid parameters' do
|
301
|
+
let(:sys_var) do
|
302
|
+
[
|
303
|
+
{'Variable_name'=>'binlog_format','Value'=>'MIXED'},
|
304
|
+
{'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
|
305
|
+
{'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
|
306
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'OFF'},
|
307
|
+
]
|
308
|
+
end
|
309
|
+
it { expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError,
|
310
|
+
/binlog_format.*\n.*log_slave_updates/) }
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe OptionalBinlogParameterChecker do
|
316
|
+
let(:subject_object) { described_class.new({}) }
|
317
|
+
|
318
|
+
describe "#check_result" do
|
319
|
+
let(:sys_var) do
|
320
|
+
[
|
321
|
+
{'Variable_name'=>'net_read_timeout','Value'=>600},
|
322
|
+
{'Variable_name'=>'net_write_timeout','Value'=>600},
|
323
|
+
{'Variable_name'=>'wait_timeout','Value'=>60}
|
324
|
+
]
|
325
|
+
end
|
326
|
+
subject { subject_object.check_result(sys_var) }
|
327
|
+
|
328
|
+
context 'where parameters are valid' do
|
329
|
+
it { expect{subject}.not_to raise_error }
|
330
|
+
end
|
331
|
+
|
332
|
+
context 'where parameters contain required paramters' do
|
333
|
+
let(:sys_var) do
|
334
|
+
[
|
335
|
+
{'Variable_name'=>'binlog_format','Value'=>'ROW'},
|
336
|
+
{'Variable_name'=>'binlog_checksum','Value'=>'NONE'},
|
337
|
+
{'Variable_name'=>'log_bin_use_v1_row_events','Value'=>'ON'},
|
338
|
+
{'Variable_name'=>'log_slave_updates','Value'=>'ON'},
|
339
|
+
{'Variable_name'=>'net_read_timeout','Value'=>600},
|
340
|
+
{'Variable_name'=>'net_write_timeout','Value'=>600},
|
341
|
+
{'Variable_name'=>'wait_timeout','Value'=>60},
|
342
|
+
]
|
343
|
+
end
|
344
|
+
it { expect{subject}.not_to raise_error }
|
345
|
+
end
|
346
|
+
|
347
|
+
context 'where parameters contain invalid parameters' do
|
348
|
+
let(:sys_var) do
|
349
|
+
[
|
350
|
+
{'Variable_name'=>'net_read_timeout','Value'=>2},
|
351
|
+
{'Variable_name'=>'net_write_timeout','Value'=>600},
|
352
|
+
{'Variable_name'=>'wait_timeout','Value'=>1}
|
353
|
+
]
|
354
|
+
end
|
355
|
+
it { expect{subject}.to raise_error(FlydataCore::MysqlCompatibilityError,
|
356
|
+
/^\[WARNING.*\n.*net_read_timeout.*\n.*wait_timeout/) }
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
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.
|
5
|
+
# stub: flydata 0.5.3 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "flydata"
|
9
|
-
s.version = "0.5.
|
9
|
+
s.version = "0.5.3"
|
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-
|
14
|
+
s.date = "2015-09-03"
|
15
15
|
s.description = "FlyData Agent"
|
16
16
|
s.email = "sysadmin@flydata.com"
|
17
17
|
s.executables = ["fdmysqldump", "flydata", "serverinfo"]
|
@@ -64,7 +64,7 @@ Gem::Specification.new do |s|
|
|
64
64
|
"flydata-core/spec/fluent/config_helper_spec.rb",
|
65
65
|
"flydata-core/spec/logger_spec.rb",
|
66
66
|
"flydata-core/spec/mysql/command_generator_spec.rb",
|
67
|
-
"flydata-core/spec/mysql/
|
67
|
+
"flydata-core/spec/mysql/compatibility_checker_spec.rb",
|
68
68
|
"flydata-core/spec/option_validator_spec.rb",
|
69
69
|
"flydata-core/spec/redshift/string_spec.rb",
|
70
70
|
"flydata-core/spec/spec_helper.rb",
|
@@ -219,6 +219,7 @@ Gem::Specification.new do |s|
|
|
219
219
|
"spec/flydata/util/shell_spec.rb",
|
220
220
|
"spec/flydata_spec.rb",
|
221
221
|
"spec/spec_helper.rb",
|
222
|
+
"test-suite.sh",
|
222
223
|
"tmpl/redshift_mysql_data_entry.conf.tmpl"
|
223
224
|
]
|
224
225
|
s.homepage = "http://flydata.com/"
|
@@ -111,7 +111,12 @@ module Flydata
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def check_mysql_parameters_compat
|
114
|
-
|
114
|
+
begin
|
115
|
+
FlydataCore::Mysql::OptionalBinlogParameterChecker.new(@db_opts).do_check
|
116
|
+
rescue FlydataCore::MysqlCompatibilityError => e
|
117
|
+
log_warn_stderr(e.to_s)
|
118
|
+
end
|
119
|
+
FlydataCore::Mysql::RequiredBinlogParameterChecker.new(@db_opts).do_check
|
115
120
|
end
|
116
121
|
|
117
122
|
def check_mysql_binlog_retention
|
data/test-suite.sh
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# Usage: $0 [Options]
|
4
|
+
# Specify project
|
5
|
+
# [-m] # main project
|
6
|
+
# [-c] # core project
|
7
|
+
# Test skip option
|
8
|
+
# [--skip-main]
|
9
|
+
# [--skip-core]
|
10
|
+
|
11
|
+
set -e
|
12
|
+
BASE_DIR=$(cd $(dirname $0); pwd)
|
13
|
+
|
14
|
+
#### Parse option
|
15
|
+
|
16
|
+
TEST_MODE="skip" # skip or specify
|
17
|
+
for OPT in $*
|
18
|
+
do
|
19
|
+
case $OPT in
|
20
|
+
-m) TEST_MODE='specify'; SPECIFY_M=1; shift;;
|
21
|
+
-c) TEST_MODE='specify'; SPECIFY_C=1; shift;;
|
22
|
+
--skip-main) TEST_MODE='skip'; SKIP_M=1; shift;;
|
23
|
+
--skip-core) TEST_MODE='skip'; SKIP_C=1; shift;;
|
24
|
+
esac
|
25
|
+
done
|
26
|
+
|
27
|
+
if [ "$TEST_MODE" = 'skip' ]; then
|
28
|
+
if [ "$SKIP_M" = "" ]; then SPECIFY_M=1; fi
|
29
|
+
if [ "$SKIP_C" = "" ]; then SPECIFY_C=1; fi
|
30
|
+
fi
|
31
|
+
|
32
|
+
#### Test functions
|
33
|
+
|
34
|
+
# Test flydata-agent library (flydata-agent/lib, flydata-agent/spec)
|
35
|
+
test_main() {
|
36
|
+
cd $BASE_DIR
|
37
|
+
bundle install
|
38
|
+
bundle exec rspec
|
39
|
+
}
|
40
|
+
|
41
|
+
# Test flydata-core (flydata-core/lib, flydata-core/spec)
|
42
|
+
test_core() {
|
43
|
+
cd $BASE_DIR/flydata-core
|
44
|
+
bundle install
|
45
|
+
bundle exec rspec
|
46
|
+
}
|
47
|
+
|
48
|
+
#### Main
|
49
|
+
|
50
|
+
if [ "$SPECIFY_C" = '1' ]; then
|
51
|
+
test_core
|
52
|
+
fi
|
53
|
+
|
54
|
+
if [ "$SPECIFY_M" = '1' ]; then
|
55
|
+
test_main
|
56
|
+
fi
|
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.
|
4
|
+
version: 0.5.3
|
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-
|
15
|
+
date: 2015-09-03 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rest-client
|
@@ -501,7 +501,7 @@ files:
|
|
501
501
|
- flydata-core/spec/fluent/config_helper_spec.rb
|
502
502
|
- flydata-core/spec/logger_spec.rb
|
503
503
|
- flydata-core/spec/mysql/command_generator_spec.rb
|
504
|
-
- flydata-core/spec/mysql/
|
504
|
+
- flydata-core/spec/mysql/compatibility_checker_spec.rb
|
505
505
|
- flydata-core/spec/option_validator_spec.rb
|
506
506
|
- flydata-core/spec/redshift/string_spec.rb
|
507
507
|
- flydata-core/spec/spec_helper.rb
|
@@ -656,6 +656,7 @@ files:
|
|
656
656
|
- spec/flydata/util/shell_spec.rb
|
657
657
|
- spec/flydata_spec.rb
|
658
658
|
- spec/spec_helper.rb
|
659
|
+
- test-suite.sh
|
659
660
|
- tmpl/redshift_mysql_data_entry.conf.tmpl
|
660
661
|
homepage: http://flydata.com/
|
661
662
|
licenses:
|
@@ -1,186 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'flydata-core/mysql/compatibility_checker'
|
3
|
-
|
4
|
-
module FlydataCore
|
5
|
-
module Mysql
|
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
|
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
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|