gizzmo 0.3.5 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -20,4 +20,5 @@ pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
22
  tmp
23
- gizzmo.log
23
+ gizzmo.log
24
+ *.gem
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.5
1
+ 0.4.1
data/gizzmo.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{gizzmo}
8
- s.version = "0.3.5"
8
+ s.version = "0.4.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kyle Maxwell"]
12
- s.date = %q{2010-07-26}
12
+ s.date = %q{2010-07-29}
13
13
  s.default_executable = %q{gizzmo}
14
14
  s.description = %q{Gizzmo is a command-line client for managing gizzard clusters.}
15
15
  s.email = %q{kmaxwell@twitter.com}
@@ -2,11 +2,13 @@ require "pp"
2
2
  module Gizzard
3
3
  class Command
4
4
  include Thrift
5
-
5
+
6
6
  attr_reader :buffer
7
7
 
8
- def self.run(command_name, service, global_options, argv, subcommand_options)
9
- command = Gizzard.const_get("#{classify(command_name)}Command").new(service, global_options, argv, subcommand_options)
8
+ def self.run(command_name, global_options, argv, subcommand_options, log)
9
+ command_class = Gizzard.const_get("#{classify(command_name)}Command")
10
+ service = command_class.make_service(global_options, log)
11
+ command = command_class.new(service, global_options, argv, subcommand_options)
10
12
  command.run
11
13
  if command.buffer && command_name = global_options.render.shift
12
14
  run(command_name, service, global_options, command.buffer, OpenStruct.new)
@@ -28,18 +30,30 @@ module Gizzard
28
30
  def help!(message = nil)
29
31
  raise HelpNeededError, message
30
32
  end
31
-
33
+
32
34
  def output(string)
33
35
  if global_options.render.any?
34
36
  @buffer ||= []
35
37
  @buffer << string.strip
36
- else
38
+ else
37
39
  puts string
38
40
  end
39
41
  end
40
42
  end
41
43
 
42
- class AddforwardingCommand < Command
44
+ class ShardCommand < Command
45
+ def self.make_service(global_options, log)
46
+ Gizzard::Thrift::ShardManager.new(global_options.host, global_options.port, log, global_options.dry)
47
+ end
48
+ end
49
+
50
+ class JobCommand < Command
51
+ def self.make_service(global_options, log)
52
+ Gizzard::Thrift::JobManager.new(global_options.host, global_options.port + 2, log, global_options.dry)
53
+ end
54
+ end
55
+
56
+ class AddforwardingCommand < ShardCommand
43
57
  def run
44
58
  help! if argv.length != 3
45
59
  table_id, base_id, shard_id_text = argv
@@ -48,7 +62,24 @@ module Gizzard
48
62
  end
49
63
  end
50
64
 
51
- class ForwardingsCommand < Command
65
+ class DeleteforwardingCommand < ShardCommand
66
+ def run
67
+ help! if argv.length != 3
68
+ table_id, base_id, shard_id_text = argv
69
+ shard_id = ShardId.parse(shard_id_text)
70
+ service.remove_forwarding(Forwarding.new(table_id.to_i, base_id.to_i, shard_id))
71
+ end
72
+ end
73
+
74
+ class HostsCommand < ShardCommand
75
+ def run
76
+ service.list_hostnames.map do |host|
77
+ puts host
78
+ end
79
+ end
80
+ end
81
+
82
+ class ForwardingsCommand < ShardCommand
52
83
  def run
53
84
  service.get_forwardings().sort_by do |f|
54
85
  [ ((f.table_id.abs << 1) + (f.table_id < 0 ? 1 : 0)), f.base_id ]
@@ -60,7 +91,7 @@ module Gizzard
60
91
  end
61
92
  end
62
93
 
63
- class SubtreeCommand < Command
94
+ class SubtreeCommand < ShardCommand
64
95
  def run
65
96
  @roots = []
66
97
  argv.each do |arg|
@@ -81,7 +112,7 @@ module Gizzard
81
112
  links.map { |link| roots_of(link.up_id) }.flatten
82
113
  end
83
114
  end
84
-
115
+
85
116
  def down(id, depth = 0)
86
117
  service.list_downward_links(id).map do |link|
87
118
  printable = " " * depth + link.down_id.to_unix
@@ -91,7 +122,7 @@ module Gizzard
91
122
  end
92
123
  end
93
124
 
94
- class ReloadCommand < Command
125
+ class ReloadCommand < ShardCommand
95
126
  def run
96
127
  if global_options.force || ask
97
128
  service.reload_forwardings
@@ -106,7 +137,7 @@ module Gizzard
106
137
  end
107
138
  end
108
139
 
109
- class DeleteCommand < Command
140
+ class DeleteCommand < ShardCommand
110
141
  def run
111
142
  argv.each do |arg|
112
143
  id = ShardId.parse(arg)
@@ -116,7 +147,7 @@ module Gizzard
116
147
  end
117
148
  end
118
149
 
119
- class AddlinkCommand < Command
150
+ class AddlinkCommand < ShardCommand
120
151
  def run
121
152
  up_id, down_id, weight = argv
122
153
  help! if argv.length != 3
@@ -129,7 +160,7 @@ module Gizzard
129
160
  end
130
161
  end
131
162
 
132
- class UnlinkCommand < Command
163
+ class UnlinkCommand < ShardCommand
133
164
  def run
134
165
  up_id, down_id = argv
135
166
  up_id = ShardId.parse(up_id)
@@ -138,7 +169,7 @@ module Gizzard
138
169
  end
139
170
  end
140
171
 
141
- class UnwrapCommand < Command
172
+ class UnwrapCommand < ShardCommand
142
173
  def run
143
174
  shard_ids = argv
144
175
  help! "No shards specified" if shard_ids.empty?
@@ -158,20 +189,23 @@ module Gizzard
158
189
  end
159
190
  end
160
191
 
161
- class CreateCommand < Command
192
+ class CreateCommand < ShardCommand
162
193
  def run
163
- help! if argv.length != 3
164
- host, table, class_name = argv
194
+ help! if argv.length < 2
195
+ class_name, *shard_ids = argv
165
196
  busy = 0
166
197
  source_type = command_options.source_type || ""
167
198
  destination_type = command_options.destination_type || ""
168
- service.create_shard(ShardInfo.new(shard_id = ShardId.new(host, table), class_name, source_type, destination_type, busy))
169
- service.get_shard(shard_id)
170
- output shard_id.to_unix
199
+ shard_ids.each do |id|
200
+ shard_id = ShardId.parse(id)
201
+ service.create_shard(ShardInfo.new(shard_id, class_name, source_type, destination_type, busy))
202
+ service.get_shard(shard_id)
203
+ output shard_id.to_unix
204
+ end
171
205
  end
172
206
  end
173
207
 
174
- class LinksCommand < Command
208
+ class LinksCommand < ShardCommand
175
209
  def run
176
210
  shard_ids = @argv
177
211
  shard_ids.each do |shard_id_text|
@@ -186,7 +220,7 @@ module Gizzard
186
220
  end
187
221
  end
188
222
 
189
- class InfoCommand < Command
223
+ class InfoCommand < ShardCommand
190
224
  def run
191
225
  shard_ids = @argv
192
226
  shard_ids.each do |shard_id|
@@ -196,7 +230,7 @@ module Gizzard
196
230
  end
197
231
  end
198
232
 
199
- class WrapCommand < Command
233
+ class WrapCommand < ShardCommand
200
234
  def self.derive_wrapper_shard_id(shard_info, wrapping_class_name)
201
235
  prefix_prefix = wrapping_class_name.split(".").last.downcase.gsub("shard", "") + "_"
202
236
  ShardId.new("localhost", prefix_prefix + shard_info.id.table_prefix)
@@ -223,7 +257,7 @@ module Gizzard
223
257
  end
224
258
  end
225
259
 
226
- class FindCommand < Command
260
+ class FindCommand < ShardCommand
227
261
  def run
228
262
  help!("host is a required option") unless command_options.shard_host
229
263
  service.shards_for_hostname(command_options.shard_host).each do |shard|
@@ -233,7 +267,7 @@ module Gizzard
233
267
  end
234
268
  end
235
269
 
236
- class LookupCommand < Command
270
+ class LookupCommand < ShardCommand
237
271
  def run
238
272
  table_id, source_id = @argv
239
273
  help!("Requires table id and source id") unless table_id && source_id
@@ -241,4 +275,102 @@ module Gizzard
241
275
  output shard.id.to_unix
242
276
  end
243
277
  end
278
+
279
+ class CopyCommand < ShardCommand
280
+ def run
281
+ from_shard_id_string, to_shard_id_string = @argv
282
+ help!("Requires source & destination shard id") unless from_shard_id_string && to_shard_id_string
283
+ from_shard_id = ShardId.parse(from_shard_id_string)
284
+ to_shard_id = ShardId.parse(to_shard_id_string)
285
+ service.copy_shard(from_shard_id, to_shard_id)
286
+ end
287
+ end
288
+
289
+ class BusyCommand < ShardCommand
290
+ def run
291
+ service.get_busy_shards().each { |shard_info| output shard_info.to_unix }
292
+ end
293
+ end
294
+
295
+ class SetupMigrateCommand < ShardCommand
296
+ def run
297
+ from_shard_id_string, to_shard_id_string = @argv
298
+ help!("Requires source & destination shard id") unless from_shard_id_string && to_shard_id_string
299
+ from_shard_id = ShardId.parse(from_shard_id_string)
300
+ to_shard_id = ShardId.parse(to_shard_id_string)
301
+
302
+ if service.list_upward_links(to_shard_id).size > 0
303
+ STDERR.puts "Destination shard #{to_shard_id} has links to it."
304
+ exit 1
305
+ end
306
+
307
+ write_only_shard_id = ShardId.new("localhost", "#{to_shard_id.table_prefix}_migrate_write_only")
308
+ replica_shard_id = ShardId.new("localhost", "#{to_shard_id.table_prefix}_migrate_replica")
309
+ service.create_shard(ShardInfo.new(write_only_shard_id, "com.twitter.gizzard.shards.WriteOnlyShard", "", "", 0))
310
+ service.create_shard(ShardInfo.new(replica_shard_id, "com.twitter.gizzard.shards.ReplicatingShard", "", "", 0))
311
+ service.add_link(write_only_shard_id, to_shard_id, 1)
312
+ service.list_upward_links(from_shard_id).each do |link|
313
+ service.remove_link(link.up_id, link.down_id)
314
+ service.add_link(link.up_id, replica_shard_id, link.weight)
315
+ end
316
+ service.add_link(replica_shard_id, from_shard_id, 1)
317
+ service.add_link(replica_shard_id, write_only_shard_id, 0)
318
+ service.replace_forwarding(from_shard_id, replica_shard_id)
319
+ output replica_shard_id.to_unix
320
+ end
321
+ end
322
+
323
+ class FinishMigrateCommand < ShardCommand
324
+ def run
325
+ from_shard_id_string, to_shard_id_string = @argv
326
+ help!("Requires source & destination shard id") unless from_shard_id_string && to_shard_id_string
327
+ from_shard_id = ShardId.parse(from_shard_id_string)
328
+ to_shard_id = ShardId.parse(to_shard_id_string)
329
+
330
+ write_only_shard_id = ShardId.new("localhost", "#{to_shard_id.table_prefix}_migrate_write_only")
331
+ replica_shard_id = ShardId.new("localhost", "#{to_shard_id.table_prefix}_migrate_replica")
332
+
333
+ # careful. need to validate some basic assumptions.
334
+ unless global_options.force
335
+ if service.list_upward_links(from_shard_id).map { |link| link.up_id }.to_a != [ replica_shard_id ]
336
+ STDERR.puts "Uplink from #{from_shard_id} is not a migration replica."
337
+ exit 1
338
+ end
339
+ if service.list_upward_links(to_shard_id).map { |link| link.up_id }.to_a != [ write_only_shard_id ]
340
+ STDERR.puts "Uplink from #{to_shard_id} is not a write-only barrier."
341
+ exit 1
342
+ end
343
+ if service.list_upward_links(write_only_shard_id).map { |link| link.up_id }.to_a != [ replica_shard_id ]
344
+ STDERR.puts "Uplink from write-only barrier is not a migration replica."
345
+ exit 1
346
+ end
347
+ end
348
+
349
+ service.remove_link(write_only_shard_id, to_shard_id)
350
+ service.list_upward_links(replica_shard_id).each do |link|
351
+ service.remove_link(link.up_id, link.down_id)
352
+ service.add_link(link.up_id, to_shard_id, link.weight)
353
+ end
354
+ service.replace_forwarding(replica_shard_id, to_shard_id)
355
+ service.delete_shard(replica_shard_id)
356
+ service.delete_shard(write_only_shard_id)
357
+ end
358
+ end
359
+
360
+ class InjectCommand < JobCommand
361
+ def run
362
+ priority, *jobs = @argv
363
+ help!("Requires priority") unless priority and jobs.size > 0
364
+ count = 0
365
+ jobs.each do |job|
366
+ service.inject_job(priority.to_i, job)
367
+ count += 1
368
+ # FIXME add -q --quiet option
369
+ STDERR.print "."
370
+ STDERR.print "#{count}" if count % 100 == 0
371
+ STDERR.flush
372
+ end
373
+ STDERR.print "\n"
374
+ end
375
+ end
244
376
  end
@@ -86,7 +86,7 @@ module Gizzard
86
86
  end
87
87
  end
88
88
 
89
- class ShardManager < T::ThriftService
89
+ class GizzmoService < T::ThriftService
90
90
  def initialize(host, port, log_path, dry_run = false)
91
91
  super(host, port)
92
92
  @dry = dry_run
@@ -122,8 +122,9 @@ module Gizzard
122
122
  ts = timestamp ? "#{Time.now}\t" : ""
123
123
  "#{ts}#{method_name}(#{args.map{|a| a.inspect}.join(', ')})"
124
124
  end
125
+ end
125
126
 
126
-
127
+ class ShardManager < GizzmoService
127
128
  thrift_method :create_shard, void, field(:shard, struct(ShardInfo), 1), :throws => exception(ShardException)
128
129
  thrift_method :delete_shard, void, field(:id, struct(ShardId), 1)
129
130
  thrift_method :get_shard, struct(ShardInfo), field(:id, struct(ShardId), 1)
@@ -141,6 +142,7 @@ module Gizzard
141
142
 
142
143
  thrift_method :set_forwarding, void, field(:forwarding, struct(Forwarding), 1)
143
144
  thrift_method :replace_forwarding, void, field(:old_id, struct(ShardId), 1), field(:new_id, struct(ShardId), 2)
145
+ thrift_method :remove_forwarding, void, field(:forwarding, struct(Forwarding), 1)
144
146
 
145
147
  thrift_method :get_forwarding, struct(Forwarding), field(:table_id, i32, 1), field(:base_id, i64, 2)
146
148
  thrift_method :get_forwarding_for_shard, struct(Forwarding), field(:shard_id, struct(ShardId), 1)
@@ -152,8 +154,20 @@ module Gizzard
152
154
 
153
155
  thrift_method :shards_for_hostname, list(struct(ShardInfo)), field(:hostname, string, 1)
154
156
  thrift_method :get_busy_shards, list(struct(ShardInfo))
157
+ thrift_method :list_hostnames, list(string)
155
158
 
156
159
  thrift_method :rebuild_schema, void
157
160
  end
161
+
162
+ class JobManager < GizzmoService
163
+ thrift_method :retry_errors, void
164
+ thrift_method :stop_writes, void
165
+ thrift_method :resume_writes, void
166
+ thrift_method :retry_errors_for, void, field(:priority, i32, 1)
167
+ thrift_method :stop_writes_for, void, field(:priority, i32, 1)
168
+ thrift_method :resume_writes_for, void, field(:priority, i32, 1)
169
+ thrift_method :is_writing, bool, field(:priority, i32, 1)
170
+ thrift_method :inject_job, void, field(:priority, i32, 1), field(:job, string, 2)
171
+ end
158
172
  end
159
- end
173
+ end
data/lib/gizzmo.rb CHANGED
@@ -6,7 +6,14 @@ require "ostruct"
6
6
  require "gizzard"
7
7
  require "yaml"
8
8
 
9
+ DOC_STRINGS = {
10
+ "create" => "Create shard(s) of a given Java/Scala class. If you don't know the list of available classes, you can just try a bogus class, and the exception will include a list of valid classes.",
11
+ "wrap" => "Wrapping creates a new (virtual, e.g. blocking, replicating, etc.) shard, and relinks SHARD_ID_TO_WRAP's parent links to run through the new shard.",
12
+ "inject" => "Inject jobs (as literal json) into the server. Jobs can be linefeed-terminated from stdin, or passed as arguments. Priority is server-defined, but typically lower numbers (like 1) are lower priority."
13
+ }
14
+
9
15
  ORIGINAL_ARGV = ARGV.dup
16
+ zero = File.basename($0)
10
17
 
11
18
  # Container for parsed options
12
19
  global_options = OpenStruct.new
@@ -28,10 +35,35 @@ rescue => e
28
35
  abort "Unknown error loading ~/.gizzmorc: #{e.message}"
29
36
  end
30
37
 
38
+ def split(string)
39
+ return [] unless string
40
+ a = []
41
+ tokens = string.split(/\s+/)
42
+ a << tokens.shift
43
+ tokens.each do |token|
44
+ s = a.last
45
+ if s.length + token.length + 1 < 80
46
+ s << " #{token}"
47
+ else
48
+ a << token
49
+ end
50
+ end
51
+ a
52
+ end
53
+
54
+ def separators(opts, string)
55
+ opts.separator("")
56
+ split(string).each do |substr|
57
+ opts.separator(substr)
58
+ end
59
+ opts.separator("")
60
+ end
61
+
31
62
  subcommands = {
32
63
  'create' => OptionParser.new do |opts|
33
- opts.banner = "Usage: #{$0} create [options] HOST TABLE_PREFIX CLASS_NAME"
34
-
64
+ opts.banner = "Usage: #{zero} create [options] CLASS_NAME SHARD_ID [MORE SHARD_IDS...]"
65
+ separators(opts, DOC_STRINGS["create"])
66
+
35
67
  opts.on("-s", "--source-type=TYPE") do |s|
36
68
  subcommand_options.source_type = s
37
69
  end
@@ -41,19 +73,32 @@ subcommands = {
41
73
  end
42
74
  end,
43
75
  'wrap' => OptionParser.new do |opts|
44
- opts.banner = "Usage: #{$0} wrap CLASS_NAME SHARD_ID_TO_WRAP [MORE SHARD_IDS...]"
76
+ opts.banner = "Usage: #{zero} wrap CLASS_NAME SHARD_ID_TO_WRAP [MORE SHARD_IDS...]"
77
+ separators(opts, DOC_STRINGS["wrap"])
45
78
  end,
46
79
  'subtree' => OptionParser.new do |opts|
47
- opts.banner = "Usage: #{$0} subtree SHARD_ID"
80
+ opts.banner = "Usage: #{zero} subtree SHARD_ID"
81
+ separators(opts, DOC_STRINGS["subtree"])
82
+ end,
83
+ 'hosts' => OptionParser.new do |opts|
84
+ opts.banner = "Usage: #{zero} hosts"
85
+ separators(opts, DOC_STRINGS["hosts"])
86
+ end,
87
+ 'deleteforwarding' => OptionParser.new do |opts|
88
+ opts.banner = "Usage: #{zero} deleteforwarding TABLE_ID BASE_ID SHARD_ID"
89
+ separators(opts, DOC_STRINGS["deleteforwarding"])
48
90
  end,
49
91
  'delete' => OptionParser.new do |opts|
50
- opts.banner = "Usage: #{$0} delete SHARD_ID_TO_DELETE [MORE SHARD_IDS]"
92
+ opts.banner = "Usage: #{zero} delete SHARD_ID_TO_DELETE [MORE SHARD_IDS]"
93
+ separators(opts, DOC_STRINGS["delete"])
51
94
  end,
52
95
  'addforwarding' => OptionParser.new do |opts|
53
- opts.banner = "Usage: #{$0} addforwarding TABLE_ID BASE_ID SHARD_ID"
96
+ opts.banner = "Usage: #{zero} addforwarding TABLE_ID BASE_ID SHARD_ID"
97
+ separators(opts, DOC_STRINGS["addforwarding"])
54
98
  end,
55
99
  'forwardings' => OptionParser.new do |opts|
56
- opts.banner = "Usage: #{$0} show [options]"
100
+ opts.banner = "Usage: #{zero} show [options]"
101
+ separators(opts, DOC_STRINGS["forwardings"])
57
102
 
58
103
  opts.on("-t", "--tables=IDS", "Show only the specified table ids (comma separated)") do |table_ids|
59
104
  subcommand_options.table_ids ||= []
@@ -61,10 +106,12 @@ subcommands = {
61
106
  end
62
107
  end,
63
108
  'unwrap' => OptionParser.new do |opts|
64
- opts.banner = "Usage: #{$0} unwrap SHARD_ID_TO_REMOVE [MORE SHARD_IDS]"
109
+ opts.banner = "Usage: #{zero} unwrap SHARD_ID_TO_REMOVE [MORE SHARD_IDS]"
110
+ separators(opts, DOC_STRINGS["unwrap"])
65
111
  end,
66
112
  'find' => OptionParser.new do |opts|
67
- opts.banner = "Usage: #{$0} find [options]"
113
+ opts.banner = "Usage: #{zero} find [options]"
114
+ separators(opts, DOC_STRINGS["find"])
68
115
 
69
116
  opts.on("-t", "--type=TYPE", "Return only shards of the specified TYPE") do |shard_type|
70
117
  subcommand_options.shard_type = shard_type
@@ -75,37 +122,82 @@ subcommands = {
75
122
  end
76
123
  end,
77
124
  'links' => OptionParser.new do |opts|
78
- opts.banner = "Usage: #{$0} links SHARD_ID [MORE SHARD_IDS...]"
125
+ opts.banner = "Usage: #{zero} links SHARD_ID [MORE SHARD_IDS...]"
126
+ separators(opts, DOC_STRINGS["links"])
79
127
  end,
80
128
  'info' => OptionParser.new do |opts|
81
- opts.banner = "Usage: #{$0} info SHARD_ID [MORE SHARD_IDS...]"
129
+ opts.banner = "Usage: #{zero} info SHARD_ID [MORE SHARD_IDS...]"
130
+ separators(opts, DOC_STRINGS["info"])
82
131
  end,
83
132
  'reload' => OptionParser.new do |opts|
84
- opts.banner = "Usage: #{$0} reload"
133
+ opts.banner = "Usage: #{zero} reload"
134
+ separators(opts, DOC_STRINGS["reload"])
85
135
  end,
86
136
  'addlink' => OptionParser.new do |opts|
87
- opts.banner = "Usage: #{$0} link PARENT_SHARD_ID CHILD_SHARD_ID WEIGHT"
137
+ opts.banner = "Usage: #{zero} link PARENT_SHARD_ID CHILD_SHARD_ID WEIGHT"
138
+ separators(opts, DOC_STRINGS["addlink"])
88
139
  end,
89
140
  'unlink' => OptionParser.new do |opts|
90
- opts.banner = "Usage: #{$0} unlink PARENT_SHARD_ID CHILD_SHARD_ID"
141
+ opts.banner = "Usage: #{zero} unlink PARENT_SHARD_ID CHILD_SHARD_ID"
142
+ separators(opts, DOC_STRINGS["unlink"])
91
143
  end,
92
144
  'lookup' => OptionParser.new do |opts|
93
- opts.banner = "Usage: #{$0} lookup TABLE_ID SOURCE_ID"
145
+ opts.banner = "Usage: #{zero} lookup TABLE_ID SOURCE_ID"
146
+ separators(opts, DOC_STRINGS["lookup"])
147
+ end,
148
+ 'copy' => OptionParser.new do |opts|
149
+ opts.banner = "Usage: #{zero} copy SOURCE_SHARD_ID DESTINATION_SHARD_ID"
150
+ separators(opts, DOC_STRINGS["copy"])
151
+ end,
152
+ 'busy' => OptionParser.new do |opts|
153
+ opts.banner = "Usage: #{zero} busy"
154
+ separators(opts, DOC_STRINGS["busy"])
155
+ end,
156
+ 'setup-migrate' => OptionParser.new do |opts|
157
+ opts.banner = "Usage: #{zero} setup-migrate SOURCE_SHARD_ID DESTINATION_SHARD_ID"
158
+ separators(opts, DOC_STRINGS["setup-migrate"])
159
+ end,
160
+ 'finish-migrate' => OptionParser.new do |opts|
161
+ opts.banner = "Usage: #{zero} finish-migrate SOURCE_SHARD_ID DESTINATION_SHARD_ID"
162
+ separators(opts, DOC_STRINGS["finish-migrate"])
163
+ end,
164
+ 'inject' => OptionParser.new do |opts|
165
+ opts.banner = "Usage: #{zero} inject PRIORITY JOBS..."
166
+ separators(opts, DOC_STRINGS["inject"])
94
167
  end
95
168
  }
96
169
 
97
170
  global = OptionParser.new do |opts|
98
- opts.banner = "Usage: #{$0} [global-options] SUBCOMMAND [subcommand-options]"
171
+ opts.banner = "Usage: #{zero} [global-options] SUBCOMMAND [subcommand-options]"
172
+ opts.separator ""
173
+ opts.separator "Gizzmo is a tool for manipulating the forwardings and replication structure of"
174
+ opts.separator "Gizzard-based datastores. It can also perform bulk job operations."
175
+ opts.separator ""
176
+ opts.separator "You can type `#{zero} help SUBCOMMAND` for help on a specific subcommand. It's"
177
+ opts.separator "also useful to remember that global options come *before* the subcommand, while"
178
+ opts.separator "subcommand options come *after* the subcommand."
179
+ opts.separator ""
180
+ opts.separator "You may find it useful to create a ~/.gizzmorc file, which is simply YAML"
181
+ opts.separator "key/value pairs corresponding to options you want by default. A common .gizzmorc"
182
+ opts.separator "simply contain:"
183
+ opts.separator ""
184
+ opts.separator " host: localhost"
185
+ opts.separator " port: 7917"
99
186
  opts.separator ""
100
187
  opts.separator "Subcommands:"
101
188
  subcommands.keys.compact.sort.each do |sc|
102
- opts.separator " #{sc}"
189
+ base = " #{sc}"
190
+ if doc = DOC_STRINGS[sc]
191
+ base += " " * (20 - base.length)
192
+ base += " -- "
193
+ base += doc[0..(76 - base.length)]
194
+ base += "..."
195
+ end
196
+ opts.separator base
103
197
  end
104
198
  opts.separator ""
105
- opts.separator "You can type `#{$0} help SUBCOMMAND` for help on a specific subcommand."
106
199
  opts.separator ""
107
200
  opts.separator "Global options:"
108
-
109
201
  opts.on("-H", "--host=HOSTNAME", "HOSTNAME of remote thrift service") do |host|
110
202
  global_options.host = host
111
203
  end
@@ -139,7 +231,7 @@ global = OptionParser.new do |opts|
139
231
  opts.on("-f", "--force", "Don't display confirmation dialogs") do |force|
140
232
  global_options.force = force
141
233
  end
142
-
234
+
143
235
  opts.on_tail("-v", "--version", "Show version") do
144
236
  puts GIZZMO_VERSION
145
237
  exit
@@ -182,14 +274,13 @@ unless subcommands.include?(subcommand_name)
182
274
  end
183
275
 
184
276
  log = global_options.log || "./gizzmo.log"
185
- service = Gizzard::Thrift::ShardManager.new(global_options.host, global_options.port, log, global_options.dry)
186
277
 
187
278
  while !$stdin.tty? && line = STDIN.gets
188
279
  argv << line.strip
189
280
  end
190
281
 
191
282
  begin
192
- Gizzard::Command.run(subcommand_name, service, global_options, argv, subcommand_options)
283
+ Gizzard::Command.run(subcommand_name, global_options, argv, subcommand_options, log)
193
284
  rescue HelpNeededError => e
194
285
  if e.class.name != e.message
195
286
  STDERR.puts("=" * 80)
@@ -198,7 +289,7 @@ rescue HelpNeededError => e
198
289
  end
199
290
  STDERR.puts subcommands[subcommand_name]
200
291
  exit 1
201
- rescue ThriftClient::Simple::ThriftException, Gizzard::Thrift::ShardException => e
292
+ rescue ThriftClient::Simple::ThriftException, Gizzard::Thrift::ShardException, Errno::ECONNREFUSED => e
202
293
  STDERR.puts e.message
203
294
  exit 1
204
295
  rescue Errno::EPIPE
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 5
9
- version: 0.3.5
7
+ - 4
8
+ - 1
9
+ version: 0.4.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Kyle Maxwell
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-07-26 00:00:00 -07:00
17
+ date: 2010-07-29 00:00:00 -07:00
18
18
  default_executable: gizzmo
19
19
  dependencies: []
20
20