flydata 0.3.4 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/flydata.gemspec +3 -4
- data/lib/flydata/api/data_entry.rb +5 -4
- data/lib/flydata/api_client.rb +4 -3
- data/lib/flydata/command/sync.rb +391 -307
- data/spec/flydata/command/sender_spec.rb +1 -1
- data/spec/flydata/command/sync_spec.rb +4 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3aabc1598aa6770f9f4238bae95ef42b1577c0aa
|
4
|
+
data.tar.gz: 5ba322b53b34ffaf0986542a8071c103c4d2d881
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1b6059f259512e9d7f190f9bc37c51905979adab22310f4782e92b3ebbc7156673ce48259d7f7ba6a43ae2d40755b2836b59adffd3b36d035a8ceb0ff1b9c4b
|
7
|
+
data.tar.gz: 129df374f7bbba7ed5dc70eb23bd52b46ee683521cd391c7fa0c9440f9c56649d2761210be0eca31cb8d1c05c5ed55a9ba8aadacec84085d73460af1b950303f
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.5
|
data/flydata.gemspec
CHANGED
@@ -2,14 +2,12 @@
|
|
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.3.4 ruby lib
|
6
5
|
|
7
6
|
Gem::Specification.new do |s|
|
8
7
|
s.name = "flydata"
|
9
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.5"
|
10
9
|
|
11
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
-
s.require_paths = ["lib"]
|
13
11
|
s.authors = ["Koichi Fujikawa", "Masashi Miyazaki", "Matthew Luu", "Mak Inada", "Sriram NS"]
|
14
12
|
s.date = "2015-02-28"
|
15
13
|
s.description = "FlyData Agent"
|
@@ -152,7 +150,8 @@ Gem::Specification.new do |s|
|
|
152
150
|
]
|
153
151
|
s.homepage = "http://flydata.com/"
|
154
152
|
s.licenses = ["All right reserved."]
|
155
|
-
s.
|
153
|
+
s.require_paths = ["lib"]
|
154
|
+
s.rubygems_version = "2.0.14"
|
156
155
|
s.summary = "FlyData Agent"
|
157
156
|
|
158
157
|
if s.respond_to? :specification_version then
|
@@ -7,12 +7,13 @@ module Flydata
|
|
7
7
|
super
|
8
8
|
end
|
9
9
|
|
10
|
-
def buffer_stat(data_entry_id,
|
11
|
-
|
10
|
+
def buffer_stat(data_entry_id, params = {})
|
11
|
+
tables = params[:tables] ? params[:tables].join(',') : ''
|
12
|
+
@client.get("/#{@model_name.pluralize}/#{data_entry_id}/buffer_stat/#{params[:mode]}?tables=#{tables}")
|
12
13
|
end
|
13
|
-
|
14
|
+
|
14
15
|
def cleanup_sync(data_entry_id, tables)
|
15
|
-
@client.post("/#{@model_name.pluralize}/#{data_entry_id}/cleanup_sync", nil, {tables: tables.join(',')})
|
16
|
+
@client.post("/#{@model_name.pluralize}/#{data_entry_id}/cleanup_sync", nil, {tables: tables.join(',')})
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/flydata/api_client.rb
CHANGED
@@ -63,7 +63,7 @@ module Flydata
|
|
63
63
|
if json_response.class == Hash and json_response["success"] == false
|
64
64
|
err_msg = json_response['errors'] ? json_response['errors'].to_s : "Unkown error."
|
65
65
|
raise err_msg
|
66
|
-
elsif json_response.class == Hash and json_response["auth_token"]
|
66
|
+
elsif json_response.class == Hash and json_response["auth_token"]
|
67
67
|
@credentials.write_credentials(json_response["auth_token"])
|
68
68
|
end
|
69
69
|
json_response
|
@@ -73,10 +73,11 @@ module Flydata
|
|
73
73
|
parameters = {}
|
74
74
|
parameters.merge(headers) if headers
|
75
75
|
end
|
76
|
-
def generate_auth_url(path)
|
76
|
+
def generate_auth_url(path)
|
77
77
|
token = @credentials.token
|
78
78
|
token = '' unless token
|
79
|
-
|
79
|
+
c = (path && path.include?('?')) ? '&' : '?'
|
80
|
+
"#{@flydata_api_host}#{path}#{c}auth_token=#{token}"
|
80
81
|
end
|
81
82
|
end
|
82
83
|
end
|
data/lib/flydata/command/sync.rb
CHANGED
@@ -24,11 +24,13 @@ module Flydata
|
|
24
24
|
STATUS_WAITING = 'WAITING'
|
25
25
|
STATUS_COMPLETE = 'COMPLETE'
|
26
26
|
|
27
|
-
attr_reader :
|
27
|
+
attr_reader :full_initial_sync, :full_tables, :new_tables, :ddl_tables, :input_tables
|
28
28
|
|
29
29
|
class SyncDataEntryError < StandardError
|
30
30
|
end
|
31
31
|
|
32
|
+
# Command: flydata sync
|
33
|
+
# - Arguments
|
32
34
|
def self.slop
|
33
35
|
Slop.new do
|
34
36
|
on 'c', 'skip-cleanup', 'Skip server cleanup'
|
@@ -42,7 +44,10 @@ module Flydata
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
47
|
+
# Command: flydata sync
|
48
|
+
# - Entry method
|
45
49
|
def run(*tables)
|
50
|
+
# Process check
|
46
51
|
sender = Flydata::Command::Sender.new
|
47
52
|
if (sender.process_exist?)
|
48
53
|
if tables.empty?
|
@@ -55,76 +60,40 @@ module Flydata
|
|
55
60
|
exit 1
|
56
61
|
end
|
57
62
|
|
58
|
-
|
63
|
+
# Setup instance variables
|
64
|
+
set_current_tables(tables)
|
59
65
|
|
66
|
+
# Start initial sync with check
|
67
|
+
handle_mysql_sync
|
68
|
+
|
69
|
+
# Start continuous sync by starting fluentd process
|
60
70
|
unless opts.no_flydata_start?
|
61
71
|
log_info_stdout("Starting FlyData Agent...")
|
62
72
|
Flydata::Command::Sender.new.start(quiet: true)
|
63
73
|
log_info_stdout(" -> Done")
|
64
74
|
end
|
65
75
|
|
76
|
+
# Show message
|
66
77
|
dashboard_url = "#{flydata.flydata_api_host}/dashboard"
|
67
78
|
redshift_console_url = "#{flydata.flydata_api_host}/redshift_clusters/query/new"
|
68
79
|
last_message = ALL_DONE_MESSAGE_TEMPLATE % [redshift_console_url, dashboard_url]
|
69
80
|
log_info_stdout(last_message)
|
70
81
|
end
|
71
82
|
|
83
|
+
# Public method
|
84
|
+
# - Called from Sender#start/restart
|
72
85
|
def try_mysql_sync
|
73
|
-
|
86
|
+
# Setup instance variables
|
87
|
+
set_current_tables
|
88
|
+
|
89
|
+
# Start initial sync
|
90
|
+
handle_mysql_sync
|
74
91
|
rescue SyncDataEntryError
|
75
92
|
return
|
76
93
|
end
|
77
94
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
set_current_tables(de)
|
82
|
-
verify_input_tables(tables, de['mysql_data_entry_preference']['tables'])
|
83
|
-
|
84
|
-
unless @new_tables.empty?
|
85
|
-
say("We've noticed that these tables have not been synced yet: #{@new_tables.join(", ")}")
|
86
|
-
unless @ddl_tables.empty?
|
87
|
-
say(" WARNING: We've noticed that at least one of these tables have not had their DDL generated yet.")
|
88
|
-
say(" We recommend you run our 'flydata sync:generate_table_ddl > create_table.sql'")
|
89
|
-
say(" to generate SQL to run on Redshift to create the correct tables")
|
90
|
-
say(" Without running this sql on your Redshift cluster, there may be issues with your data")
|
91
|
-
end
|
92
|
-
if ask_yes_no("Do you want to run initial sync on all of these tables now?")
|
93
|
-
tables = @initial_sync ? [] : @new_tables
|
94
|
-
initial_sync(tables, de)
|
95
|
-
else
|
96
|
-
#If generate_table_ddl has not been run for these tables, warn user
|
97
|
-
unless @ddl_tables.empty?
|
98
|
-
say(" You can generate DDL SQL for your new tables by running this command")
|
99
|
-
say(" $> flydata sync:generate_table_ddl > create_table.sql")
|
100
|
-
end
|
101
|
-
puts "Without syncing these tables, we cannot start the flydata process"
|
102
|
-
raise "Please try again"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
def initial_sync(tables, de=nil)
|
107
|
-
de = retrieve_sync_data_entry unless de
|
108
|
-
de = load_sync_info(de,tables)
|
109
|
-
validate_initial_sync_status(de, tables)
|
110
|
-
begin
|
111
|
-
flush_buffer_and_stop unless @initial_sync
|
112
|
-
sync_mysql_to_redshift(de)
|
113
|
-
rescue ServerDataProcessingTimeout => e
|
114
|
-
ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
|
115
|
-
ee.description = <<EOS
|
116
|
-
Data processing is taking more than expected. Please contact support@flydata.com to check the system status.
|
117
|
-
Once checked, you can resume sync with the following command.
|
118
|
-
|
119
|
-
flydata start
|
120
|
-
|
121
|
-
EOS
|
122
|
-
ee.set_backtrace e.backtrace
|
123
|
-
raise ee
|
124
|
-
end
|
125
|
-
complete
|
126
|
-
end
|
127
|
-
|
95
|
+
# Command: flydata sync:flush
|
96
|
+
# - Arguments
|
128
97
|
def self.slop_flush
|
129
98
|
Slop.new do
|
130
99
|
on 'f', 'skip-flush', 'Skip server flush'
|
@@ -132,9 +101,11 @@ EOS
|
|
132
101
|
end
|
133
102
|
end
|
134
103
|
|
135
|
-
|
104
|
+
# Command: flydata sync:flush
|
105
|
+
# - Entry method
|
106
|
+
def flush(*tables)
|
136
107
|
begin
|
137
|
-
flush_buffer_and_stop
|
108
|
+
flush_buffer_and_stop(tables)
|
138
109
|
rescue ServerDataProcessingTimeout => e
|
139
110
|
ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
|
140
111
|
ee.description = <<EOS
|
@@ -147,6 +118,8 @@ EOS
|
|
147
118
|
log_info_stdout("Buffers have been flushed and the sender process has been stopped.")
|
148
119
|
end
|
149
120
|
|
121
|
+
# Command: flydata sync:reset
|
122
|
+
# - Arguments
|
150
123
|
def self.slop_reset
|
151
124
|
Slop.new do
|
152
125
|
on 'c', 'client', 'Resets client only.'
|
@@ -154,19 +127,22 @@ EOS
|
|
154
127
|
end
|
155
128
|
end
|
156
129
|
|
130
|
+
# Command: flydata sync:reset
|
131
|
+
# - Entry method
|
157
132
|
def reset(*tables)
|
133
|
+
# Flush client buffer
|
158
134
|
msg = tables.empty? ? '' : " for these tables : #{tables.join(" ")}"
|
159
135
|
return unless ask_yes_no("This resets the current sync#{msg}. Are you sure?")
|
160
136
|
sender = Flydata::Command::Sender.new
|
161
137
|
sender.flush_client_buffer # TODO We should rather delete buffer files
|
162
138
|
sender.stop
|
163
139
|
|
164
|
-
|
165
|
-
|
166
|
-
|
140
|
+
# Set instance variables
|
141
|
+
de = data_entry
|
142
|
+
set_current_tables(tables)
|
167
143
|
|
168
144
|
begin
|
169
|
-
wait_for_server_buffer(SERVER_DATA_PROCESSING_TIMEOUT)
|
145
|
+
wait_for_server_buffer(timeout: SERVER_DATA_PROCESSING_TIMEOUT, tables: target_tables_for_api)
|
170
146
|
rescue ServerDataProcessingTimeout => e
|
171
147
|
ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
|
172
148
|
ee.description = <<EOS
|
@@ -179,20 +155,24 @@ EOS
|
|
179
155
|
ee.set_backtrace e.backtrace
|
180
156
|
raise ee
|
181
157
|
end
|
182
|
-
|
183
|
-
|
158
|
+
|
159
|
+
# Cleanup tables on server
|
160
|
+
cleanup_sync_server(de, @input_tables) unless opts.client?
|
161
|
+
|
162
|
+
# Delete local files
|
163
|
+
sync_fm = create_sync_file_manager(de)
|
184
164
|
delete_files = [
|
185
165
|
sync_fm.dump_file_path,
|
186
166
|
sync_fm.dump_pos_path,
|
187
167
|
sync_fm.mysql_table_marshal_dump_path,
|
188
168
|
sync_fm.sync_info_file,
|
189
|
-
sync_fm.table_position_file_paths(
|
190
|
-
sync_fm.table_binlog_pos_paths(
|
191
|
-
sync_fm.table_binlog_pos_init_paths(
|
192
|
-
sync_fm.table_rev_file_paths(
|
193
|
-
sync_fm.table_ddl_file_paths(
|
169
|
+
sync_fm.table_position_file_paths(*@input_tables),
|
170
|
+
sync_fm.table_binlog_pos_paths(*@input_tables),
|
171
|
+
sync_fm.table_binlog_pos_init_paths(*@input_tables),
|
172
|
+
sync_fm.table_rev_file_paths(*@input_tables),
|
173
|
+
sync_fm.table_ddl_file_paths(*@input_tables)
|
194
174
|
]
|
195
|
-
delete_files << sync_fm.binlog_path if
|
175
|
+
delete_files << sync_fm.binlog_path if @input_tables.empty? or @full_tables.empty?
|
196
176
|
delete_files.flatten.each do |path|
|
197
177
|
FileUtils.rm(path) if File.exists?(path)
|
198
178
|
end
|
@@ -200,75 +180,11 @@ EOS
|
|
200
180
|
log_info_stdout("Reset completed successfully.")
|
201
181
|
end
|
202
182
|
|
203
|
-
|
204
|
-
start_time = Time.now
|
205
|
-
log_info_stdout("Waiting for the server buffer to get empty.")
|
206
|
-
prev_message =nil
|
207
|
-
while (status = check) && (status['state'] == 'processing')
|
208
|
-
prev_message = status['message']
|
209
|
-
if timeout > 0 && Time.now - start_time > timeout
|
210
|
-
raise ServerDataProcessingTimeout.new
|
211
|
-
end
|
212
|
-
print_progress(status)
|
213
|
-
sleep 10
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def wait_for_server_data_processing(timeout = 0)
|
218
|
-
state = :PROCESS
|
219
|
-
start_time = Time.now
|
220
|
-
log_info_stdout("Uploading data to Redshift...")
|
221
|
-
sleep 10
|
222
|
-
status = nil
|
223
|
-
prev_message =nil
|
224
|
-
while (status = check)
|
225
|
-
if state == :PROCESS && status['state'] == 'uploading'
|
226
|
-
log_info_stdout(" -> Done")
|
227
|
-
state = :UPLOAD
|
228
|
-
log_info_stdout("Finishing data upload...")
|
229
|
-
end
|
230
|
-
|
231
|
-
#TODO This is based on a temporary option
|
232
|
-
if state == :UPLOAD && opts.ff?
|
233
|
-
log_info_stdout("Skip checking for pending uploads")
|
234
|
-
break
|
235
|
-
end
|
236
|
-
|
237
|
-
if status['message'] != prev_message
|
238
|
-
# making some progress. Reset timer
|
239
|
-
start_time = Time.now
|
240
|
-
end
|
241
|
-
prev_message = status['message']
|
242
|
-
if timeout > 0 && Time.now - start_time > timeout
|
243
|
-
raise ServerDataProcessingTimeout.new
|
244
|
-
end
|
245
|
-
print_progress(status)
|
246
|
-
sleep 10
|
247
|
-
end
|
248
|
-
if (state == :PROCESS)
|
249
|
-
# :UPLOAD state was skipped due to no data
|
250
|
-
log_info_stdout(" -> Done")
|
251
|
-
log_info_stdout("Finishing data upload...")
|
252
|
-
end
|
253
|
-
log_info_stdout(" -> Done")
|
254
|
-
end
|
255
|
-
|
256
|
-
def check
|
257
|
-
de = retrieve_sync_data_entry
|
258
|
-
retry_on(RestClient::Exception) do
|
259
|
-
status = do_check(de)
|
260
|
-
if status['complete']
|
261
|
-
nil
|
262
|
-
else
|
263
|
-
status
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
183
|
+
# Depricated Command: flydata sync:skip
|
268
184
|
# skip initial sync
|
269
185
|
def skip
|
270
|
-
de =
|
271
|
-
sync_fm =
|
186
|
+
de = data_entry
|
187
|
+
sync_fm = create_sync_file_manager(de)
|
272
188
|
binlog_path = sync_fm.binlog_path
|
273
189
|
sync_fm.close
|
274
190
|
`touch #{binlog_path}`
|
@@ -277,6 +193,8 @@ EOS
|
|
277
193
|
log_info_stdout("Run 'flydata start' to start continuous sync.")
|
278
194
|
end
|
279
195
|
|
196
|
+
# Command: flydata sync:generate_table_ddl
|
197
|
+
# - Arguments
|
280
198
|
def self.slop_generate_table_ddl
|
281
199
|
Slop.new do
|
282
200
|
on 'c', 'ctl-only', 'Only generate FlyData Control definitions'
|
@@ -286,166 +204,77 @@ EOS
|
|
286
204
|
end
|
287
205
|
end
|
288
206
|
|
207
|
+
# Command: flydata sync:generate_table_ddl
|
208
|
+
# - Entry method
|
289
209
|
def generate_table_ddl(*tables)
|
290
|
-
|
210
|
+
# Compatibility check
|
211
|
+
de = data_entry
|
291
212
|
dp = flydata.data_port.get
|
292
213
|
Flydata::MysqlCompatibilityCheck.new(dp, de['mysql_data_entry_preference']).check
|
293
|
-
do_generate_table_ddl(de, tables)
|
294
|
-
end
|
295
214
|
|
296
|
-
|
215
|
+
# Set instance variables
|
216
|
+
set_current_tables(tables)
|
297
217
|
|
298
|
-
|
299
|
-
return unless input_tables
|
300
|
-
inval_table = []
|
301
|
-
input_tables.each do |tab|
|
302
|
-
inval_table << tab unless all_tables.include?(tab)
|
303
|
-
end
|
304
|
-
raise "These tables are not registered tables: #{inval_table.join(", ")}" unless inval_table.empty?
|
218
|
+
do_generate_table_ddl(de)
|
305
219
|
end
|
306
220
|
|
307
|
-
|
308
|
-
sync_fm = Flydata::FileUtil::SyncFileManager.new(de)
|
309
|
-
full_tables = de['mysql_data_entry_preference']['tables']
|
310
|
-
|
311
|
-
@new_tables = sync_fm.get_new_table_list(full_tables, "pos")
|
312
|
-
@ddl_tables = sync_fm.get_new_table_list(full_tables, "generated_ddl")
|
313
|
-
|
314
|
-
@initial_sync = (@new_tables == full_tables)
|
315
|
-
sync_fm.close
|
316
|
-
end
|
221
|
+
private
|
317
222
|
|
318
|
-
|
319
|
-
sync_fm = Flydata::FileUtil::SyncFileManager.new(de)
|
320
|
-
dump_pos_info = sync_fm.load_dump_pos
|
321
|
-
fp = sync_fm.dump_file_path
|
322
|
-
sync_fm.close
|
223
|
+
# Initial sync
|
323
224
|
|
324
|
-
|
325
|
-
|
326
|
-
raise "FlyData Sync was interrupted with invalid state. Run 'flydata sync:reset#{tables.empty? ? '' : ' ' + tables.join(' ')}' first."
|
327
|
-
end
|
328
|
-
end
|
225
|
+
def handle_mysql_sync
|
226
|
+
de = data_entry
|
329
227
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
mp['tables'] = (mp['tables'].split(",") + mp['tables_append_only'].split(",")).uniq
|
338
|
-
else
|
339
|
-
mp['tables'] = mp['tables'].split(",").uniq
|
228
|
+
unless @new_tables.empty?
|
229
|
+
say("We've noticed that these tables have not been synced yet: #{@new_tables.join(", ")}")
|
230
|
+
unless @ddl_tables.empty?
|
231
|
+
say(" WARNING: We've noticed that at least one of these tables have not had their DDL generated yet.")
|
232
|
+
say(" We recommend you run our 'flydata sync:generate_table_ddl > create_table.sql'")
|
233
|
+
say(" to generate SQL to run on Redshift to create the correct tables")
|
234
|
+
say(" Without running this sql on your Redshift cluster, there may be issues with your data")
|
340
235
|
end
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
begin
|
352
|
-
flydata.data_entry.cleanup_sync(de['id'], tables)
|
353
|
-
rescue RestClient::RequestTimeout, RestClient::GatewayTimeout
|
354
|
-
# server is taking time to cleanup. Try again
|
355
|
-
retry
|
236
|
+
if ask_yes_no("Do you want to run initial sync on all of these tables now?")
|
237
|
+
initial_sync(de)
|
238
|
+
else
|
239
|
+
#If generate_table_ddl has not been run for these tables, warn user
|
240
|
+
unless @ddl_tables.empty?
|
241
|
+
say(" You can generate DDL SQL for your new tables by running this command")
|
242
|
+
say(" $> flydata sync:generate_table_ddl > create_table.sql")
|
243
|
+
end
|
244
|
+
puts "Without syncing these tables, we cannot start the flydata process"
|
245
|
+
raise "Please try again"
|
356
246
|
end
|
357
247
|
end
|
358
|
-
until worker.join(5)
|
359
|
-
print "."
|
360
|
-
end
|
361
|
-
puts
|
362
|
-
log_info_stdout("Done.")
|
363
|
-
end
|
364
|
-
|
365
|
-
def do_check(de)
|
366
|
-
flydata.data_entry.buffer_stat(de['id'], env_mode)
|
367
248
|
end
|
368
249
|
|
369
|
-
def
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
schema_name = (de['schema_name'] || nil)
|
382
|
-
|
383
|
-
mp = de['mysql_data_entry_preference']
|
384
|
-
|
385
|
-
set_current_tables(de)
|
386
|
-
|
387
|
-
tables = opts.all_tables? ? mp['tables'] : (tables.empty? ? @new_tables : tables)
|
388
|
-
raise "There are no valid unsynced tables, if you want to just get ddl for all tables, please run \`flydata sync:generate_table_ddl --all-tables\`" if tables.empty?
|
389
|
-
|
390
|
-
%w(host username database).each do |conf_name|
|
391
|
-
raise "MySQL `#{conf_name}` is neither defined in the data entry nor the local config file" if mp[conf_name].to_s.empty?
|
392
|
-
end
|
393
|
-
if tables.empty?
|
394
|
-
raise "`tables` (or `tables_append_only`) is neither defined in the data entry nor the local config file"
|
395
|
-
end
|
250
|
+
def initial_sync(de)
|
251
|
+
# Load sync information from file
|
252
|
+
load_sync_info(de)
|
253
|
+
validate_initial_sync_status
|
254
|
+
begin
|
255
|
+
flush_buffer_and_stop(target_tables_for_api) unless @full_initial_sync
|
256
|
+
sync_mysql_to_redshift(de)
|
257
|
+
rescue ServerDataProcessingTimeout => e
|
258
|
+
ee = ServerDataProcessingTimeout.new("Delayed Data Processing")
|
259
|
+
ee.description = <<EOS
|
260
|
+
Data processing is taking more than expected. Please contact support@flydata.com to check the system status.
|
261
|
+
Once checked, you can resume sync with the following command.
|
396
262
|
|
397
|
-
|
263
|
+
flydata start
|
398
264
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
create_flydata_ctl_table = @initial_sync
|
403
|
-
while !stdout.eof?
|
404
|
-
begin
|
405
|
-
mysql_tabledef = FlydataCore::TableDef::MysqlTableDef.create(stdout, skip_primary_key_check: opts.skip_primary_key_check?)
|
406
|
-
if mysql_tabledef.nil?
|
407
|
-
# stream had no more create table definition
|
408
|
-
break
|
409
|
-
end
|
410
|
-
flydata_tabledef = mysql_tabledef.to_flydata_tabledef
|
411
|
-
puts FlydataCore::TableDef::RedshiftTableDef.from_flydata_tabledef(flydata_tabledef, flydata_ctl_table: create_flydata_ctl_table, schema_name: schema_name, ctl_only: opts.ctl_only?)
|
412
|
-
rescue FlydataCore::TableDefError=> e
|
413
|
-
error_list << e.err_hash
|
414
|
-
next
|
415
|
-
end
|
416
|
-
create_flydata_ctl_table = false
|
417
|
-
end
|
418
|
-
errors = ""
|
419
|
-
while !stderr.eof?
|
420
|
-
line = stderr.gets.gsub('mysqldump: ', '')
|
421
|
-
errors << line unless /Warning: Using a password on the command line interface can be insecure./ === line
|
422
|
-
end
|
423
|
-
raise errors unless errors.empty?
|
424
|
-
end
|
425
|
-
unless error_list.empty?
|
426
|
-
log_error_stderr("We have noticed the following error(s):")
|
427
|
-
group_error = error_list.group_by {|d| d[:error]}
|
428
|
-
group_error.each_key do |a|
|
429
|
-
log_error_stderr("The following table(s) have #{a}:")
|
430
|
-
group_error[a].each do |hash|
|
431
|
-
log_error_stderr(" - #{hash[:table]}") if hash[:table]
|
432
|
-
end
|
433
|
-
end
|
434
|
-
log_error_stderr("Please fix the above error(s) to try to sync those table(s) or contact us for further help.")
|
265
|
+
EOS
|
266
|
+
ee.set_backtrace e.backtrace
|
267
|
+
raise ee
|
435
268
|
end
|
436
|
-
|
437
|
-
|
438
|
-
sync_fm = Flydata::FileUtil::SyncFileManager.new(de)
|
439
|
-
sync_fm.mark_generated_tables(tables_without_error)
|
440
|
-
sync_fm.close
|
269
|
+
complete(de)
|
441
270
|
end
|
442
271
|
|
443
272
|
def sync_mysql_to_redshift(de)
|
444
273
|
dp = flydata.data_port.get
|
445
|
-
sync_fm =
|
274
|
+
sync_fm = create_sync_file_manager(de)
|
446
275
|
|
447
276
|
# Check client condition
|
448
|
-
if File.exists?(sync_fm.binlog_path) and @
|
277
|
+
if File.exists?(sync_fm.binlog_path) and @full_initial_sync
|
449
278
|
raise "Already synchronized. If you want to do initial sync, run 'flydata sync:reset'"
|
450
279
|
end
|
451
280
|
|
@@ -454,7 +283,7 @@ EOS
|
|
454
283
|
Flydata::Command::Conf.new.copy_templates
|
455
284
|
end
|
456
285
|
generate_mysqldump(de, sync_fm, !opts.dump_stream?) do |mysqldump_io, db_bytesize|
|
457
|
-
sync_fm.save_sync_info(@
|
286
|
+
sync_fm.save_sync_info(@full_initial_sync, de['mysql_data_entry_preference']['tables'])
|
458
287
|
parse_mysqldump_and_send(mysqldump_io, dp, de, sync_fm, db_bytesize)
|
459
288
|
end
|
460
289
|
wait_for_mysqldump_processed(dp, de, sync_fm)
|
@@ -481,7 +310,7 @@ EOS
|
|
481
310
|
return call_block_or_return_io(fp, &block)
|
482
311
|
end
|
483
312
|
|
484
|
-
tables =
|
313
|
+
tables = target_tables
|
485
314
|
tables ||= '<all tables>'
|
486
315
|
data_servers = de['mysql_data_entry_preference']['data_servers'] ? "\n data servers: #{de['mysql_data_entry_preference']['data_servers']}" : ""
|
487
316
|
|
@@ -507,7 +336,7 @@ EOM
|
|
507
336
|
Flydata::MysqlCompatibilityCheck.new(dp, de['mysql_data_entry_preference'], dump_dir: fp, backup_dir: sync_fm.backup_dir).check
|
508
337
|
log_info_stdout("Checking database size...")
|
509
338
|
|
510
|
-
db_bytesize = Flydata::Parser::Mysql::DatabaseSizeCheck.new(de['mysql_data_entry_preference']).get_db_bytesize
|
339
|
+
db_bytesize = Flydata::Parser::Mysql::DatabaseSizeCheck.new(de['mysql_data_entry_preference'].merge('tables' => target_tables)).get_db_bytesize
|
511
340
|
log_info_stdout(" -> #{as_size(db_bytesize)} (#{db_bytesize} byte)")
|
512
341
|
|
513
342
|
if file_dump
|
@@ -523,17 +352,16 @@ EOM
|
|
523
352
|
end
|
524
353
|
end
|
525
354
|
|
526
|
-
|
527
355
|
log_info_stdout("Exporting data from database.")
|
528
356
|
log_info_stdout("This process can take hours depending on data size and load on your database. Please be patient...")
|
529
357
|
if file_dump
|
530
358
|
Flydata::Parser::Mysql::MysqlDumpGeneratorNoMasterData.
|
531
|
-
new(de['mysql_data_entry_preference']).dump(fp)
|
359
|
+
new(de['mysql_data_entry_preference'].merge('tables' => target_tables)).dump(fp)
|
532
360
|
log_info_stdout(" -> Done")
|
533
361
|
call_block_or_return_io(fp, &block)
|
534
362
|
else
|
535
363
|
Flydata::Parser::Mysql::MysqlDumpGeneratorNoMasterData.
|
536
|
-
new(de['mysql_data_entry_preference']).dump {|io| block.call(io, db_bytesize)}
|
364
|
+
new(de['mysql_data_entry_preference'].merge('tables' => target_tables)).dump {|io| block.call(io, db_bytesize)}
|
537
365
|
end
|
538
366
|
else
|
539
367
|
exit 1
|
@@ -603,7 +431,7 @@ EOM
|
|
603
431
|
log_info_stdout("Resuming... Last processed table: #{option[:table_name]}")
|
604
432
|
else
|
605
433
|
#If its a new sync, ensure server side resources are clean
|
606
|
-
cleanup_sync_server(de,
|
434
|
+
cleanup_sync_server(de, target_tables_for_api) unless opts.skip_cleanup?
|
607
435
|
end
|
608
436
|
log_info_stdout("Sending data to FlyData Server...")
|
609
437
|
|
@@ -671,38 +499,85 @@ EOM
|
|
671
499
|
return unless dump_pos_info[:status] == STATUS_WAITING
|
672
500
|
binlog_pos = dump_pos_info[:binlog_pos]
|
673
501
|
|
674
|
-
wait_for_server_data_processing(
|
675
|
-
|
676
|
-
sync_fm.save_table_binlog_pos(
|
502
|
+
wait_for_server_data_processing(
|
503
|
+
timeout: SERVER_DATA_PROCESSING_TIMEOUT, tables: target_tables_for_api)
|
504
|
+
sync_fm.save_table_binlog_pos(target_tables, binlog_pos)
|
677
505
|
sync_fm.save_dump_pos(STATUS_COMPLETE, '', -1, binlog_pos)
|
678
506
|
end
|
679
507
|
|
680
|
-
|
508
|
+
# option: timeout, tables
|
509
|
+
def wait_for_server_data_processing(option = {})
|
510
|
+
timeout = option[:timeout] || 0
|
511
|
+
tables = option[:tables] || []
|
681
512
|
|
682
|
-
|
513
|
+
state = :PROCESS
|
514
|
+
start_time = Time.now
|
515
|
+
log_info_stdout("Uploading data to Redshift...")
|
516
|
+
sleep 10
|
517
|
+
status = nil
|
518
|
+
prev_message =nil
|
519
|
+
while (status = check_server_status(tables))
|
520
|
+
if state == :PROCESS && status['state'] == 'uploading'
|
521
|
+
log_info_stdout(" -> Done")
|
522
|
+
state = :UPLOAD
|
523
|
+
log_info_stdout("Finishing data upload...")
|
524
|
+
end
|
683
525
|
|
684
|
-
|
526
|
+
#TODO This is based on a temporary option
|
527
|
+
if state == :UPLOAD && opts.ff?
|
528
|
+
log_info_stdout("Skip checking for pending uploads")
|
529
|
+
break
|
530
|
+
end
|
685
531
|
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
532
|
+
if status['message'] != prev_message
|
533
|
+
# making some progress. Reset timer
|
534
|
+
start_time = Time.now
|
535
|
+
end
|
536
|
+
prev_message = status['message']
|
537
|
+
if timeout > 0 && Time.now - start_time > timeout
|
538
|
+
raise ServerDataProcessingTimeout.new
|
539
|
+
end
|
540
|
+
print_progress(status)
|
541
|
+
sleep 10
|
542
|
+
end
|
543
|
+
if (state == :PROCESS)
|
544
|
+
# :UPLOAD state was skipped due to no data
|
545
|
+
log_info_stdout(" -> Done")
|
546
|
+
log_info_stdout("Finishing data upload...")
|
547
|
+
end
|
548
|
+
log_info_stdout(" -> Done")
|
549
|
+
end
|
692
550
|
|
693
|
-
|
694
|
-
|
551
|
+
def check_server_status(tables = [])
|
552
|
+
de = data_entry
|
553
|
+
retry_on(RestClient::Exception) do
|
554
|
+
status = do_check_server_status(de, tables)
|
555
|
+
if status['complete']
|
556
|
+
nil
|
557
|
+
else
|
558
|
+
status
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
695
562
|
|
696
|
-
def
|
697
|
-
de
|
698
|
-
|
563
|
+
def do_check_server_status(de, tables = [])
|
564
|
+
flydata.data_entry.buffer_stat(de['id'], mode: env_mode, tables: tables)
|
565
|
+
end
|
566
|
+
|
567
|
+
def print_progress(buffer_stat)
|
568
|
+
message = buffer_stat['message']
|
569
|
+
log_info_stdout(message) unless message.nil? || message.empty?
|
570
|
+
end
|
571
|
+
|
572
|
+
def complete(de)
|
573
|
+
sync_fm = create_sync_file_manager(de)
|
699
574
|
info = sync_fm.load_dump_pos
|
700
575
|
if info[:status] == STATUS_COMPLETE
|
701
|
-
if @
|
576
|
+
if @full_initial_sync
|
702
577
|
sync_fm.save_binlog(info[:binlog_pos])
|
703
578
|
end
|
704
|
-
sync_fm.install_table_binlog_files(
|
705
|
-
sync_fm.reset_table_position_files(
|
579
|
+
sync_fm.install_table_binlog_files(target_tables)
|
580
|
+
sync_fm.reset_table_position_files(target_tables)
|
706
581
|
sync_fm.delete_dump_file
|
707
582
|
sync_fm.backup_dump_dir
|
708
583
|
else
|
@@ -719,29 +594,238 @@ Thank you for using FlyData!
|
|
719
594
|
h.to_json
|
720
595
|
end
|
721
596
|
|
722
|
-
|
723
|
-
|
597
|
+
# Sync reset
|
598
|
+
|
599
|
+
def wait_for_server_buffer(option = {})
|
600
|
+
timeout = option[:timeout] || 0
|
601
|
+
tables = option[:tables] || []
|
602
|
+
|
603
|
+
start_time = Time.now
|
604
|
+
log_info_stdout("Waiting for the server buffer to get empty.")
|
605
|
+
prev_message =nil
|
606
|
+
while (status = check_server_status(tables)) && (status['state'] == 'processing')
|
607
|
+
prev_message = status['message']
|
608
|
+
if timeout > 0 && Time.now - start_time > timeout
|
609
|
+
raise ServerDataProcessingTimeout.new
|
610
|
+
end
|
611
|
+
print_progress(status)
|
612
|
+
sleep 10
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
def cleanup_sync_server(de, tables = [])
|
617
|
+
print "Cleaning the server."
|
618
|
+
log_info("Cleaning the server.")
|
619
|
+
worker = Thread.new do
|
620
|
+
begin
|
621
|
+
flydata.data_entry.cleanup_sync(de['id'], tables)
|
622
|
+
rescue RestClient::RequestTimeout, RestClient::GatewayTimeout
|
623
|
+
# server is taking time to cleanup. Try again
|
624
|
+
retry
|
625
|
+
end
|
626
|
+
end
|
627
|
+
until worker.join(5)
|
628
|
+
print "."
|
629
|
+
end
|
630
|
+
puts
|
631
|
+
log_info_stdout("Done.")
|
632
|
+
end
|
633
|
+
|
634
|
+
# Generate table ddl
|
635
|
+
|
636
|
+
def do_generate_table_ddl(de)
|
637
|
+
if `which mysqldump`.empty?
|
638
|
+
raise "mysqldump is not installed. mysqldump is required to run the command"
|
639
|
+
end
|
640
|
+
|
641
|
+
error_list = []
|
642
|
+
schema_name = (de['schema_name'] || nil)
|
724
643
|
mp = de['mysql_data_entry_preference']
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
644
|
+
|
645
|
+
tables = opts.all_tables? ? @full_tables : (@input_tables.empty? ? @new_tables : @input_tables)
|
646
|
+
raise "There are no valid unsynced tables, if you want to just get ddl for all tables, please run \`flydata sync:generate_table_ddl --all-tables\`" if tables.empty?
|
647
|
+
|
648
|
+
%w(host username database).each do |conf_name|
|
649
|
+
raise "MySQL `#{conf_name}` is neither defined in the data entry nor the local config file" if mp[conf_name].to_s.empty?
|
730
650
|
end
|
651
|
+
if tables.empty?
|
652
|
+
raise "`tables` (or `tables_append_only`) is neither defined in the data entry nor the local config file"
|
653
|
+
end
|
654
|
+
|
655
|
+
command = Util::MysqlUtil.generate_mysql_ddl_dump_cmd(mp.merge(tables: tables))
|
656
|
+
|
657
|
+
Open3.popen3(command) do |stdin, stdout, stderr|
|
658
|
+
stdin.close
|
659
|
+
stdout.set_encoding("utf-8") # mysqldump output must be in UTF-8
|
660
|
+
create_flydata_ctl_table = @full_initial_sync
|
661
|
+
while !stdout.eof?
|
662
|
+
begin
|
663
|
+
mysql_tabledef = FlydataCore::TableDef::MysqlTableDef.create(stdout, skip_primary_key_check: opts.skip_primary_key_check?)
|
664
|
+
if mysql_tabledef.nil?
|
665
|
+
# stream had no more create table definition
|
666
|
+
break
|
667
|
+
end
|
668
|
+
flydata_tabledef = mysql_tabledef.to_flydata_tabledef
|
669
|
+
puts FlydataCore::TableDef::RedshiftTableDef.from_flydata_tabledef(flydata_tabledef, flydata_ctl_table: create_flydata_ctl_table, schema_name: schema_name, ctl_only: opts.ctl_only?)
|
670
|
+
rescue FlydataCore::TableDefError=> e
|
671
|
+
error_list << e.err_hash
|
672
|
+
next
|
673
|
+
end
|
674
|
+
create_flydata_ctl_table = false
|
675
|
+
end
|
676
|
+
errors = ""
|
677
|
+
while !stderr.eof?
|
678
|
+
line = stderr.gets.gsub('mysqldump: ', '')
|
679
|
+
errors << line unless /Warning: Using a password on the command line interface can be insecure./ === line
|
680
|
+
end
|
681
|
+
raise errors unless errors.empty?
|
682
|
+
end
|
683
|
+
unless error_list.empty?
|
684
|
+
log_error_stderr("We have noticed the following error(s):")
|
685
|
+
group_error = error_list.group_by {|d| d[:error]}
|
686
|
+
group_error.each_key do |a|
|
687
|
+
log_error_stderr("The following table(s) have #{a}:")
|
688
|
+
group_error[a].each do |hash|
|
689
|
+
log_error_stderr(" - #{hash[:table]}") if hash[:table]
|
690
|
+
end
|
691
|
+
end
|
692
|
+
log_error_stderr("Please fix the above error(s) to try to sync those table(s) or contact us for further help.")
|
693
|
+
end
|
694
|
+
tables_without_error = tables - error_list.inject([]){|arr, err| arr << err[:table] if err[:table]}
|
695
|
+
|
696
|
+
sync_fm = create_sync_file_manager(de)
|
697
|
+
sync_fm.mark_generated_tables(tables_without_error)
|
731
698
|
sync_fm.close
|
732
|
-
de
|
733
699
|
end
|
734
700
|
|
735
|
-
|
701
|
+
|
702
|
+
ALL_DONE_MESSAGE_TEMPLATE = <<-EOM
|
703
|
+
|
704
|
+
Congratulations! FlyData has started synchronizing your database tables.
|
705
|
+
|
706
|
+
What's next?
|
707
|
+
|
708
|
+
- Check data on Redshift (%s)
|
709
|
+
- Check your FlyData usage on the FlyData Dashboard (%s)
|
710
|
+
- To manage the FlyData Agent, use the 'flydata' command (type 'flydata' for help)
|
711
|
+
- If you encounter an issue,
|
712
|
+
please check our documentation (https://www.flydata.com/docs/) or
|
713
|
+
contact our customer support team (support@flydata.com)
|
714
|
+
|
715
|
+
Thank you for using FlyData!
|
716
|
+
EOM
|
717
|
+
|
718
|
+
# Sync flush
|
719
|
+
|
720
|
+
def flush_buffer_and_stop(tables = [])
|
736
721
|
sender = Flydata::Command::Sender.new
|
737
722
|
sender.flush_client_buffer
|
738
723
|
if opts.skip_flush?
|
739
724
|
log_info_stdout("Skip waiting for server data processing.")
|
740
725
|
else
|
741
|
-
wait_for_server_data_processing(
|
726
|
+
wait_for_server_data_processing(
|
727
|
+
timeout: SERVER_DATA_PROCESSING_TIMEOUT, tables: tables)
|
742
728
|
end
|
743
729
|
sender.stop(quiet: true)
|
744
730
|
end
|
731
|
+
|
732
|
+
# Utility methods
|
733
|
+
|
734
|
+
def set_current_tables(input_tables = nil)
|
735
|
+
de = data_entry
|
736
|
+
sync_fm = create_sync_file_manager(de)
|
737
|
+
@input_tables = input_tables || []
|
738
|
+
@full_tables = de['mysql_data_entry_preference']['tables']
|
739
|
+
|
740
|
+
@new_tables = sync_fm.get_new_table_list(@full_tables, "pos")
|
741
|
+
@ddl_tables = sync_fm.get_new_table_list(@full_tables, "generated_ddl")
|
742
|
+
|
743
|
+
@full_initial_sync = (@new_tables == @full_tables)
|
744
|
+
|
745
|
+
sync_fm.close
|
746
|
+
|
747
|
+
verify_input_tables(@input_tables, @full_tables)
|
748
|
+
end
|
749
|
+
|
750
|
+
def validate_initial_sync_status
|
751
|
+
sync_fm = create_sync_file_manager
|
752
|
+
dump_pos_info = sync_fm.load_dump_pos
|
753
|
+
fp = sync_fm.dump_file_path
|
754
|
+
sync_fm.close
|
755
|
+
|
756
|
+
# status is parsing but dumpfile doesn't exist due to streaming -> raise error
|
757
|
+
if dump_pos_info[:status] == STATUS_PARSING && !File.exists?(fp)
|
758
|
+
raise "FlyData Sync was interrupted with invalid state. Run 'flydata sync:reset#{@input_tables.join(',')}' first."
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
def load_sync_info(de)
|
763
|
+
# for debug
|
764
|
+
raise "!AssertionError. set_current_tables needs to be called in advance" if @full_tables.nil?
|
765
|
+
|
766
|
+
sync_fm = create_sync_file_manager(de)
|
767
|
+
if (rs = sync_fm.load_sync_info)
|
768
|
+
@full_initial_sync = rs[:initial_sync]
|
769
|
+
@input_tables = rs[:tables]
|
770
|
+
end
|
771
|
+
sync_fm.close
|
772
|
+
de
|
773
|
+
end
|
774
|
+
|
775
|
+
def target_tables
|
776
|
+
if @full_initial_sync
|
777
|
+
@full_tables
|
778
|
+
elsif !@input_tables.empty?
|
779
|
+
@input_tables
|
780
|
+
else
|
781
|
+
@new_tables
|
782
|
+
end
|
783
|
+
end
|
784
|
+
|
785
|
+
# return empty array if full sync
|
786
|
+
def target_tables_for_api
|
787
|
+
if @full_initial_sync
|
788
|
+
[]
|
789
|
+
elsif !@input_tables.empty?
|
790
|
+
@input_tables
|
791
|
+
else
|
792
|
+
@new_tables
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
796
|
+
def data_entry
|
797
|
+
@de ||= retrieve_sync_data_entry
|
798
|
+
end
|
799
|
+
|
800
|
+
def retrieve_sync_data_entry
|
801
|
+
de = retrieve_data_entries.first unless de
|
802
|
+
raise "There are no data entries." unless de
|
803
|
+
case de['type']
|
804
|
+
when 'RedshiftMysqlDataEntry'
|
805
|
+
mp = de['mysql_data_entry_preference']
|
806
|
+
if mp['tables_append_only']
|
807
|
+
mp['tables'] = (mp['tables'].split(",") + mp['tables_append_only'].split(",")).uniq
|
808
|
+
else
|
809
|
+
mp['tables'] = mp['tables'].split(",").uniq
|
810
|
+
end
|
811
|
+
else
|
812
|
+
raise SyncDataEntryError, "No supported data entry. Only mysql-redshift sync is supported."
|
813
|
+
end
|
814
|
+
de
|
815
|
+
end
|
816
|
+
|
817
|
+
def create_sync_file_manager(de = data_entry)
|
818
|
+
Flydata::FileUtil::SyncFileManager.new(de)
|
819
|
+
end
|
820
|
+
|
821
|
+
def verify_input_tables(input_tables, all_tables)
|
822
|
+
return unless input_tables
|
823
|
+
inval_table = []
|
824
|
+
input_tables.each do |tab|
|
825
|
+
inval_table << tab unless all_tables.include?(tab)
|
826
|
+
end
|
827
|
+
raise "These tables are not registered tables: #{inval_table.join(", ")}" unless inval_table.empty?
|
828
|
+
end
|
745
829
|
end
|
746
830
|
end
|
747
831
|
end
|
@@ -18,7 +18,7 @@ module Flydata
|
|
18
18
|
allow(Kernel).to receive(:sleep)
|
19
19
|
allow_any_instance_of(Flydata::Api::DataPort).to receive(:get).and_return("Wibble")
|
20
20
|
allow_any_instance_of(Flydata::AgentCompatibilityCheck).to receive(:check).and_return(true)
|
21
|
-
Flydata::Command::Sync.any_instance.should_receive(:
|
21
|
+
Flydata::Command::Sync.any_instance.should_receive(:try_mysql_sync).and_return("Wobble")
|
22
22
|
end
|
23
23
|
|
24
24
|
context "as daemon" do
|
@@ -65,6 +65,10 @@ module Flydata
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
describe '#do_generate_table_ddl' do
|
68
|
+
before do
|
69
|
+
allow(subject).to receive(:data_entry).and_return(default_data_entry)
|
70
|
+
subject.send(:set_current_tables)
|
71
|
+
end
|
68
72
|
shared_examples 'throws an error' do
|
69
73
|
it "throws an error" do
|
70
74
|
expect {
|
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.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Koichi Fujikawa
|
@@ -592,7 +592,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
592
592
|
version: '0'
|
593
593
|
requirements: []
|
594
594
|
rubyforge_project:
|
595
|
-
rubygems_version: 2.
|
595
|
+
rubygems_version: 2.0.14
|
596
596
|
signing_key:
|
597
597
|
specification_version: 4
|
598
598
|
summary: FlyData Agent
|