flydata 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -10,6 +10,7 @@ gem "fluentd", "0.10.46"
10
10
  gem "ruby-binlog", ">= 1.0.1"
11
11
  gem "fluent-plugin-mysql-binlog", "~> 0.0.2"
12
12
  gem "mysql2", "~> 0.3.11"
13
+ gem "slop"
13
14
 
14
15
  group :development do
15
16
  gem "bundler"
data/Gemfile.lock CHANGED
@@ -97,6 +97,7 @@ GEM
97
97
  ruby-binlog (1.0.1)
98
98
  ruby-prof (0.14.2)
99
99
  sigdump (0.2.2)
100
+ slop (3.4.6)
100
101
  sqlite3 (1.3.8)
101
102
  thread_safe (0.1.3)
102
103
  atomic
@@ -124,5 +125,6 @@ DEPENDENCIES
124
125
  rspec
125
126
  ruby-binlog (>= 1.0.1)
126
127
  ruby-prof
128
+ slop
127
129
  sqlite3
128
130
  timecop
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.8
1
+ 0.1.9
data/flydata.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "flydata"
8
- s.version = "0.1.8"
8
+ s.version = "0.1.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Koichi Fujikawa"]
12
- s.date = "2014-06-23"
12
+ s.date = "2014-07-01"
13
13
  s.description = "FlyData Command Line Interface"
14
14
  s.email = "sysadmin@flydata.co"
15
15
  s.executables = ["fdmysqldump", "flydata"]
@@ -77,6 +77,7 @@ Gem::Specification.new do |s|
77
77
  "spec/fluent_plugins_spec_helper.rb",
78
78
  "spec/fly_data_model_spec.rb",
79
79
  "spec/flydata/api/data_entry_spec.rb",
80
+ "spec/flydata/cli_spec.rb",
80
81
  "spec/flydata/command/sender_spec.rb",
81
82
  "spec/flydata/command/sync_spec.rb",
82
83
  "spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb",
@@ -90,6 +91,7 @@ Gem::Specification.new do |s|
90
91
  "spec/flydata/table_def/mysqldump_test_table_enum.dump",
91
92
  "spec/flydata/table_def/mysqldump_test_table_multi_pk.dump",
92
93
  "spec/flydata/table_def/mysqldump_test_table_no_pk.dump",
94
+ "spec/flydata/table_def/mysqldump_test_unsigned.dump",
93
95
  "spec/flydata/table_def/redshift_table_def_spec.rb",
94
96
  "spec/flydata/util/encryptor_spec.rb",
95
97
  "spec/flydata_spec.rb",
@@ -99,7 +101,7 @@ Gem::Specification.new do |s|
99
101
  s.homepage = "http://flydata.co/"
100
102
  s.licenses = ["All right reserved."]
101
103
  s.require_paths = ["lib"]
102
- s.rubygems_version = "1.8.23"
104
+ s.rubygems_version = "1.8.24"
103
105
  s.summary = "FlyData CLI"
104
106
 
105
107
  if s.respond_to? :specification_version then
@@ -115,6 +117,7 @@ Gem::Specification.new do |s|
115
117
  s.add_runtime_dependency(%q<ruby-binlog>, [">= 1.0.1"])
116
118
  s.add_runtime_dependency(%q<fluent-plugin-mysql-binlog>, ["~> 0.0.2"])
117
119
  s.add_runtime_dependency(%q<mysql2>, ["~> 0.3.11"])
120
+ s.add_runtime_dependency(%q<slop>, [">= 0"])
118
121
  s.add_development_dependency(%q<bundler>, [">= 0"])
119
122
  s.add_development_dependency(%q<jeweler>, [">= 0"])
120
123
  s.add_development_dependency(%q<rspec>, [">= 0"])
@@ -134,6 +137,7 @@ Gem::Specification.new do |s|
134
137
  s.add_dependency(%q<ruby-binlog>, [">= 1.0.1"])
135
138
  s.add_dependency(%q<fluent-plugin-mysql-binlog>, ["~> 0.0.2"])
136
139
  s.add_dependency(%q<mysql2>, ["~> 0.3.11"])
140
+ s.add_dependency(%q<slop>, [">= 0"])
137
141
  s.add_dependency(%q<bundler>, [">= 0"])
138
142
  s.add_dependency(%q<jeweler>, [">= 0"])
139
143
  s.add_dependency(%q<rspec>, [">= 0"])
@@ -154,6 +158,7 @@ Gem::Specification.new do |s|
154
158
  s.add_dependency(%q<ruby-binlog>, [">= 1.0.1"])
155
159
  s.add_dependency(%q<fluent-plugin-mysql-binlog>, ["~> 0.0.2"])
156
160
  s.add_dependency(%q<mysql2>, ["~> 0.3.11"])
161
+ s.add_dependency(%q<slop>, [">= 0"])
157
162
  s.add_dependency(%q<bundler>, [">= 0"])
158
163
  s.add_dependency(%q<jeweler>, [">= 0"])
159
164
  s.add_dependency(%q<rspec>, [">= 0"])
data/lib/flydata/cli.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'slop'
2
+
1
3
  module Flydata
2
4
  class Cli
3
5
  include Helpers
@@ -15,7 +17,11 @@ module Flydata
15
17
  first_arg = @args.shift
16
18
  cmd, sub_cmd = parse_command(first_arg)
17
19
  cmd_cls = "Flydata::Command::#{cmd.capitalize}".constantize
18
- cmd_obj = cmd_cls.new
20
+ # Command class can define options for each subcommand by defining method "slop_subcommandname"
21
+ slop_method = sub_cmd ? "slop_#{sub_cmd}".to_sym : :slop
22
+ options = cmd_cls.respond_to?(slop_method) ? cmd_cls.send(slop_method) : Slop.new(strict: true)
23
+ options.parse!(@args)
24
+ cmd_obj = cmd_cls.new(options)
19
25
  sub_cmd ? cmd_obj.send(sub_cmd,*@args) : cmd_obj.run(*@args)
20
26
  else
21
27
  raise 'no command given'
@@ -1,9 +1,11 @@
1
1
  module Flydata
2
2
  module Command
3
3
  class Base
4
- def initialize
4
+ def initialize(options = Slop.new)
5
5
  @api_client = ApiClient.instance
6
+ @opts = options
6
7
  end
8
+ attr_reader :opts
7
9
  def flydata; @api_client end
8
10
 
9
11
  def retrieve_data_entries
@@ -1,25 +1,36 @@
1
1
  module Flydata
2
2
  module Command
3
3
  class Sender < Base
4
- def start(show_final_message = true)
4
+ def self.slop_start
5
+ Slop.new do
6
+ on 'n', 'no-daemon', 'Start FlyData agent as a regular program'
7
+ end
8
+ end
9
+ def start(options_or_show_final_message = {show_final_message: true}) # For backward compatibility. Use only as options going forward
10
+ if options_or_show_final_message.kind_of? Hash
11
+ options = options_or_show_final_message
12
+ else
13
+ options = {show_final_message: options_or_show_final_message}
14
+ end
5
15
  # Check if process exist
6
16
  if process_exist?
7
- say("Process is still running. Please stop process first.")
17
+ say("Process is still running. Please stop process first.") unless options[:quiet]
8
18
  return
9
19
  end
10
20
 
11
- wait_until_server_ready
21
+ wait_until_server_ready(options)
12
22
 
13
23
  # Start sender(fluentd) process
14
- say('Starting sender process.')
24
+ say('Starting sender process.') unless options[:quiet]
15
25
  Dir.chdir(FLYDATA_HOME){
16
- system("fluentd -d #{FLYDATA_HOME}/flydata.pid -l #{FLYDATA_HOME}/flydata.log -c #{FLYDATA_HOME}/flydata.conf -p #{File.dirname(__FILE__)}/../fluent-plugins")
26
+ daemon_option = opts.no_daemon? ? "" : "-d #{FLYDATA_HOME}/flydata.pid"
27
+ Kernel.system("fluentd #{daemon_option} -l #{FLYDATA_HOME}/flydata.log -c #{FLYDATA_HOME}/flydata.conf -p #{File.dirname(__FILE__)}/../fluent-plugins")
17
28
  }
18
- sleep 5
29
+ Kernel.sleep 5
19
30
 
20
- wait_until_client_ready
31
+ wait_until_client_ready(options)
21
32
  #wait_until_logs_uploaded
22
- if show_final_message
33
+ if options[:show_final_message] && !options[:quiet]
23
34
  data_port = flydata.data_port.get
24
35
  say("Go to your Dashboard! #{flydata.flydata_api_host}/data_ports/#{data_port['id']}")
25
36
  say <<EOF
@@ -34,43 +45,43 @@ EOF
34
45
  end
35
46
 
36
47
  say('Stopping sender process.') unless options[:quiet]
37
- if system("kill `cat #{FLYDATA_HOME}/flydata.pid`") and wait_until_client_stop
48
+ if Kernel.system("kill `cat #{FLYDATA_HOME}/flydata.pid`") and wait_until_client_stop(options)
38
49
  say('Done.') unless options[:quiet]
39
50
  return true
40
51
  end
41
52
  raise 'Something has gone wrong..'
42
53
  end
43
- def flush_client_buffer
54
+ def flush_client_buffer(options = {})
44
55
  unless process_exist?
45
56
  return true if client_buffer_empty?
46
- say("Process doesn't exist. But, the client buffer is not empty!!")
47
- start false
57
+ say("Process doesn't exist. But, the client buffer is not empty!!") unless options[:quiet]
58
+ start(options)
48
59
  end
49
60
 
50
- say('Stopping input plugins and flushing the client buffer.')
51
- system("kill -USR1 `cat #{FLYDATA_HOME}/flydata.pid`")
61
+ say('Stopping input plugins and flushing the client buffer.') unless options[:quiet]
62
+ Kernel.system("kill -USR1 `cat #{FLYDATA_HOME}/flydata.pid`")
52
63
 
53
64
  retry_count = 12
54
65
  1.upto(retry_count) do |i|
55
66
  return true if client_buffer_empty?
56
- say("Waiting for the buffer to get empty... (#{i}/#{retry_count})")
57
- sleep 5
67
+ say("Waiting for the buffer to get empty... (#{i}/#{retry_count})") unless options[:quiet]
68
+ Kernel.sleep 5
58
69
  end
59
70
 
60
71
  raise 'Something is wrong! Unable to flush client buffer'
61
72
  end
62
- def restart
73
+ def restart(options = {})
63
74
  if process_exist?
64
- say('Restarting sender process.')
65
- if system("kill -HUP `cat #{FLYDATA_HOME}/flydata.pid`")
66
- say('Done.')
75
+ say('Restarting sender process.') unless options[:quiet]
76
+ if Kernel.system("kill -HUP `cat #{FLYDATA_HOME}/flydata.pid`")
77
+ say('Done.') unless options[:quiet]
67
78
  return true
68
79
  else
69
80
  raise 'Something has gone wrong..'
70
81
  end
71
82
  else
72
- say("Process doesn't exist.")
73
- start
83
+ say("Process doesn't exist.") unless options[:quiet]
84
+ start(options)
74
85
  end
75
86
  end
76
87
  def status
@@ -80,9 +91,13 @@ EOF
80
91
  say("Process is not running.")
81
92
  end
82
93
  end
83
- def kill_all
84
- if system("ps ax | grep 'flydata' | grep -v grep | awk '{print \"kill \" $1}' | sh")
85
- say("Done.")
94
+ def process_exist?
95
+ # Returns true if the process is running
96
+ `[ -f #{FLYDATA_HOME}/flydata.pid ] && pgrep -P \`cat #{FLYDATA_HOME}/flydata.pid\``.to_i > 0
97
+ end
98
+ def kill_all(optiosn = {})
99
+ if Kernel.system("ps ax | grep 'flydata' | grep -v grep | awk '{print \"kill \" $1}' | sh")
100
+ say("Done.") unless options[:quiet]
86
101
  return true
87
102
  else
88
103
  raise 'Something has gone wrong...'
@@ -90,52 +105,52 @@ EOF
90
105
  end
91
106
 
92
107
  private
93
- def wait_until_server_ready
108
+ def wait_until_server_ready(options = {})
94
109
  retry_count = 10
95
110
  1.upto(retry_count) do |i|
96
111
  return true if server_ready?
97
- say("Waiting for the server side to become active... (#{i}/#{retry_count})")
98
- sleep 30
112
+ say("Waiting for the server side to become active... (#{i}/#{retry_count})") unless options[:quiet]
113
+ Kernel.sleep 30
99
114
  end
100
115
  false
101
116
  end
102
- def wait_until_client_ready
117
+ def wait_until_client_ready(options = {})
103
118
  retry_count = 10
104
119
  1.upto(retry_count) do |i|
105
120
  if client_ready?
106
- say("Done! Client is ready now.")
121
+ say("Done! Client is ready now.") unless options[:quiet]
107
122
  return true
108
123
  end
109
124
  if process_died?
110
125
  raise "Client could not been launched. Detail here #{FLYDATA_HOME}/flydata.log"
111
126
  end
112
- say("Waiting for the client side to become active... (#{i}/#{retry_count})")
113
- sleep 10
127
+ say("Waiting for the client side to become active... (#{i}/#{retry_count})") unless options[:quiet]
128
+ Kernel.sleep 10
114
129
  end
115
130
  raise "Somthing has gone wrong... Please try setup command again."
116
131
  end
117
- def wait_until_client_stop
132
+ def wait_until_client_stop(options = {})
118
133
  retry_count = 5
119
134
  1.upto(retry_count) do |i|
120
135
  return true unless process_exist?
121
- say("Waiting for the client to stop... (#{i}/#{retry_count})")
122
- sleep 3
136
+ say("Waiting for the client to stop... (#{i}/#{retry_count})") unless options[:quiet]
137
+ Kernel.sleep 3
123
138
  end
124
139
  false
125
140
  end
126
- def wait_until_logs_uploaded
127
- say('Starting to check the upload from your server.')
141
+ def wait_until_logs_uploaded(options = {})
142
+ say('Starting to check the upload from your server.') unless options[:quiet]
128
143
  data_port = flydata.data_port.get
129
144
  data_port_id = data_port['id']
130
145
 
131
146
  retry_count = 10
132
147
  1.upto(retry_count) do |i|
133
148
  if uploaded_successfully?(data_port_id)
134
- say("Uploading your logs correctly.")
149
+ say("Uploading your logs correctly.") unless options[:quiet]
135
150
  return true
136
151
  end
137
- say("Waiting logs uploading... (#{i}/#{retry_count})")
138
- sleep 30
152
+ say("Waiting logs uploading... (#{i}/#{retry_count})") unless options[:quiet]
153
+ Kernel.sleep 30
139
154
  end
140
155
  raise 'Cannot confirm that your logs exist on the FlyData server. Something has gone wrong..'
141
156
  end
@@ -147,10 +162,6 @@ EOF
147
162
  def client_ready?
148
163
  process_exist?
149
164
  end
150
- def process_exist?
151
- # Returns true if the process is running
152
- `[ -f #{FLYDATA_HOME}/flydata.pid ] && pgrep -P \`cat #{FLYDATA_HOME}/flydata.pid\``.to_i > 0
153
- end
154
165
  def process_died?
155
166
  # Returns true if the process is running
156
167
  !!(`tail -n 1 #{FLYDATA_HOME}/flydata.log` =~ /process died within/)
@@ -159,9 +170,9 @@ EOF
159
170
  res = flydata.get("/data_ports/#{data_port_id}/tail.json")
160
171
  res and res['logs'] and res['logs'].size > 0
161
172
  end
162
- def client_buffer_empty?
173
+ def client_buffer_empty?(options = {})
163
174
  client_buffer = File.join(FLYDATA_HOME, 'buffer')
164
- say("Checking the client buffer #{client_buffer}")
175
+ say("Checking the client buffer #{client_buffer}") unless options[:quiet]
165
176
  Dir.glob("#{client_buffer}/*").empty?
166
177
  end
167
178
  end
@@ -19,40 +19,93 @@ module Flydata
19
19
  files.map { |f| File.expand_path(f) }.map { |f| File.directory?(f) ? f + "/" : f }
20
20
  end
21
21
 
22
+ ALL_DONE_MESSAGE_TEMPLATE = <<-EOM
23
+ Congratulations! FlyData has started uploading your data.
24
+
25
+ To complete your installation and to add the `flydata` command, please run the
26
+ following from the command line.
27
+
28
+ $ source ~/.bashrc
29
+
30
+ What's next?
31
+
32
+ - Check data on Redshift (%s)
33
+ - Check your FlyData usage on the FlyData Dashboard (%s)
34
+ - To manage the FlyData Agent, use the 'flydata' command (type 'flydata' for
35
+ help)
36
+ - If you encounter an issue,
37
+ please check our documentation (https://www.flydata.com/docs/) or
38
+ contact our customer support team (support@flydata.com)
39
+
40
+ Thank you for using FlyData!
41
+ EOM
42
+
43
+ INITIAL_SYNC_MESSAGE_TEMPLATE = <<-EOM
44
+ FlyData Agent has been installed on your server successfully.
45
+
46
+
47
+ What's next?
48
+
49
+ 1. Generate a script to create tables on Redshift by running the following command.
50
+
51
+ $ flydata sync:generate_table_ddl > create_table.sql
52
+
53
+ 2. Create tables on Redshift by running the 'create_table.sql' script on your Redshift cluster.
54
+ The script is auto-generated from your MySQL tables. You can also edit the script to add extra Redshift parameters such as distkey and sortkey. Once you run the script and create tables in Redshift, you are ready for the next step.
55
+
56
+ 3. Start Sync
57
+ Run the following command on your server. The command will start synchronizing data between MySQL and Redshift!
58
+
59
+ $ flydata sync
60
+
61
+ EOM
62
+
63
+ NO_DE_SYNC_CANCEL_MESSAGE_TEMPLATE = <<-EOM
64
+ FlyData Agent has been installed on your server successfully.
65
+
66
+
67
+ What's next?
68
+
69
+ 1. Create a data entry from the dashboard (%s)
70
+
71
+ 2. Reinstall FlyData Agent by running the install command on the dashboard
72
+
73
+ EOM
74
+
22
75
  def initial_run
23
- last_message = nil
24
- run do
76
+ data_port = flydata.data_port.get
77
+ dashboard_url = "#{flydata.flydata_api_host}/data_ports/#{data_port['id']}"
78
+ redshift_console_url = "#{flydata.flydata_api_host}/redshift_clusters/query/new"
79
+ last_message = ALL_DONE_MESSAGE_TEMPLATE % [redshift_console_url, dashboard_url]
80
+
81
+ run(quiet: true) do
25
82
  Flydata::Command::Conf.new.copy_templates
26
83
  puts
27
- shown_redshift_entries = (show_registered_redshift_entries)
28
- shown_mysql_data_entries = show_registered_redshift_mysql_data_entries
29
- if shown_redshift_entries
30
- Flydata::Command::Sender.new.stop
84
+ if has_registered_redshift_entries?
85
+ Flydata::Command::Sender.new.stop(quiet: true)
31
86
  true
32
- elsif shown_mysql_data_entries
87
+ elsif has_registered_redshift_mysql_data_entries?
33
88
  de = retrieve_data_entries.first
34
89
  if File.exists?(Flydata::FileUtil::SyncFileManager.new(de).binlog_path)
35
- Flydata::Command::Sender.new.stop
90
+ Flydata::Command::Sender.new.stop(quiet: true)
36
91
  true
37
92
  else
38
- last_message = "\n! NOTE: Initial synchronization of MySQL database is required.\n" +
39
- " Please run 'flydata sync' to start synchronization."
93
+ last_message = INITIAL_SYNC_MESSAGE_TEMPLATE
40
94
  false
41
95
  end
42
96
  else
43
- _run
97
+ need_restart = _run
98
+ last_message = NO_DE_SYNC_CANCEL_MESSAGE_TEMPLATE % [dashboard_url] unless need_restart
99
+ need_restart
44
100
  end
45
101
  end
46
- puts
47
- print_usage
48
- puts "Completed setup of FlyData!"
49
- puts last_message if last_message
102
+ puts last_message
50
103
  end
51
104
 
52
- def run(&block)
105
+ def run(options = {}, &block)
53
106
  Flydata::Command::Login.new.run unless flydata.credentials.authenticated?
54
107
  ret = block_given? ? yield : _run
55
- Flydata::Command::Sender.new.restart if ret
108
+ Flydata::Command::Sender.new.restart(options) if ret
56
109
  end
57
110
 
58
111
  private
@@ -82,6 +135,10 @@ module Flydata
82
135
  end
83
136
  end
84
137
 
138
+ def has_registered_redshift_mysql_data_entries?
139
+ has_registered_entries?('RedshiftMysqlDataEntry')
140
+ end
141
+
85
142
  #### redshift backup mode
86
143
  def start_redshift_mode
87
144
  newline
@@ -99,6 +156,10 @@ module Flydata
99
156
  end
100
157
  end
101
158
 
159
+ def has_registered_redshift_entries?
160
+ has_registered_entries?('RedshiftFileDataEntry')
161
+ end
162
+
102
163
  def ask_adding_new_redshift
103
164
  puts "Start registration of a new entry:"
104
165
  newline
@@ -236,6 +297,12 @@ module Flydata
236
297
  end
237
298
  end
238
299
 
300
+ def has_registered_entries?(type='FlyDataEntry')
301
+ data_entries = retrieve_data_entries
302
+ data_entries = data_entries.select {|de| de['type'] == type}
303
+ data_entries && data_entries.size > 0
304
+ end
305
+
239
306
  def choose_log_path_from_examples
240
307
  candidates = (`ls #{LOG_PATH_EXAMPLES.join(' ')} 2>/dev/null`).split(/\s+/)
241
308
  candidates = candidates.find_all{|path| File.readable?(path)}