gizzmo 0.3.5 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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