lib/gizzmo.rb in gizzmo-0.11.0 vs lib/gizzmo.rb in gizzmo-0.11.1

- old
+ new

@@ -20,23 +20,26 @@ "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.", "links" => "List parent & child links for shards.", "lookup" => "Lookup the shard id that holds the record for a given table / source_id.", "markbusy" => "Mark a shard as busy.", "pair" => "Report the replica pairing structure for a list of hosts.", - "reload" => "Instruct an appserver to reload its nameserver state.", + "reload" => "Instruct application servers to reload the nameserver state.", "report" => "Show each unique replica structure for a given list of shards. Usually this shard list comes from << gizzmo forwardings | awk '{ print $3 }' >>.", "setup-replica" => "Add a replica to be parallel to an existing replica, in write-only mode, ready to be copied to.", "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.", } ORIGINAL_ARGV = ARGV.dup zero = File.basename($0) # Container for parsed options -global_options = OpenStruct.new -global_options.render = [] -global_options.framed = false +global_options = OpenStruct.new +global_options.port = 7920 +global_options.injector_port = 7921 +global_options.render = [] +global_options.framed = false + subcommand_options = OpenStruct.new # Leftover arguments argv = nil @@ -76,14 +79,33 @@ opts.separator("") end def load_config(options, filename) YAML.load(File.open(filename)).each do |k, v| + v = v.split(",").map {|h| h.strip } if k == "hosts" options.send("#{k}=", v) end end +def add_scheduler_opts(subcommand_options, opts) + opts.on("--max-copies=COUNT", "Limit max simultaneous copies to COUNT.") do |c| + (subcommand_options.scheduler_options ||= {})[:max_copies] = c.to_i + end + opts.on("--copies-per-host=COUNT", "Limit max copies per individual destination host to COUNT") do |c| + (subcommand_options.scheduler_options ||= {})[:copies_per_host] = c.to_i + end + opts.on("--poll-interval=SECONDS", "Sleep SECONDS between polling for copy status") do |c| + (subcommand_options.scheduler_options ||= {})[:poll_interval] = c.to_i + end + opts.on("--copy-wrapper=TYPE", "Wrap copy destination shards with TYPE. default WriteOnlyShard") do |t| + (subcommand_options.scheduler_options ||= {})[:copy_wrapper] = t + end + opts.on("--no-progress", "Do not show progress bar at bottom.") do + (subcommand_options.scheduler_options ||= {})[:no_progress] = true + end +end + subcommands = { 'create' => OptionParser.new do |opts| opts.banner = "Usage: #{zero} create [options] CLASS_NAME SHARD_ID [MORE SHARD_IDS...]" separators(opts, DOC_STRINGS["create"]) @@ -104,11 +126,11 @@ separators(opts, DOC_STRINGS["rebalance"]) opts.on("-w", "--write-only=CLASS") do |w| subcommand_options.write_only_shard = w end - opts.on("-h", "--hosts=list") do |h| + opts.on("-h", "--shard-hosts=list") do |h| subcommand_options.hosts = h end opts.on("-x", "--exclude-hosts=list") do |x| subcommand_options.exclude_hosts = x end @@ -147,14 +169,10 @@ end, 'addforwarding' => OptionParser.new do |opts| opts.banner = "Usage: #{zero} addforwarding TABLE_ID BASE_ID SHARD_ID" separators(opts, DOC_STRINGS["addforwarding"]) end, - 'currentforwarding' => OptionParser.new do |opts| - opts.banner = "Usage: #{zero} currentforwarding SOURCE_ID [ANOTHER_SOURCE_ID...]" - separators(opts, DOC_STRINGS["addforwarding"]) - end, 'forwardings' => OptionParser.new do |opts| opts.banner = "Usage: #{zero} forwardings [options]" separators(opts, DOC_STRINGS["forwardings"]) opts.on("-t", "--tables=IDS", "Show only the specified table ids (comma separated)") do |table_ids| @@ -175,11 +193,11 @@ opts.on("-t", "--type=TYPE", "Return only shards of the specified TYPE") do |shard_type| subcommand_options.shard_type = shard_type end - opts.on("-H", "--host=HOST", "HOST of shard") do |shard_host| + opts.on("-h", "--shard-host=HOST", "HOST of shard") do |shard_host| subcommand_options.shard_host = shard_host end end, 'links' => OptionParser.new do |opts| opts.banner = "Usage: #{zero} links SHARD_ID [MORE SHARD_IDS...]" @@ -265,10 +283,50 @@ separators(opts, DOC_STRINGS["flush"]) opts.on("--all", "Flush all error queues.") do subcommand_options.flush_all = true end + end, + 'add-host' => OptionParser.new do |opts| + opts.banner = "Usage: #{zero} add-host HOSTS" + separators(opts, DOC_STRINGS["add-host"]) + end, + 'remove-host' => OptionParser.new do |opts| + opts.banner = "Usage: #{zero} remove-host HOST" + separators(opts, DOC_STRINGS["remove-host"]) + end, + 'list-hosts' => OptionParser.new do |opts| + opts.banner = "Usage: #{zero} list-hosts" + separators(opts, DOC_STRINGS["list-hosts"]) + end, + 'topology' => OptionParser.new do |opts| + opts.banner = "Usage: #{zero} topology [options]" + separators(opts, DOC_STRINGS["topology"]) + + opts.on("--forwardings", "Show topology of forwardings instead of counts") do + subcommand_options.forwardings = true + end + end, + 'transform-tree' => OptionParser.new do |opts| + opts.banner = "Usage: #{zero} transform-tree [options] ROOT_SHARD_ID TEMPLATE" + separators(opts, DOC_STRINGS['transform-tree']) + + add_scheduler_opts subcommand_options, opts + + opts.on("-q", "--quiet", "Do not display transformation info (only valid with --force)") do + subcommand_options.quiet = true + end + end, + 'transform' => OptionParser.new do |opts| + opts.banner = "Usage: #{zero} transform [options] FROM_TEMPLATE TO_TEMPLATE" + separators(opts, DOC_STRINGS['transform']) + + add_scheduler_opts subcommand_options, opts + + opts.on("-q", "--quiet", "Do not display transformation info (only valid with --force)") do + subcommand_options.quiet = true + end end } if ENV['GIZZMORC'] load_config(global_options, ENV['GIZZMORC']) @@ -286,11 +344,11 @@ opts.separator "" opts.separator "You may find it useful to create a ~/.gizzmorc file, which is simply YAML" opts.separator "key/value pairs corresponding to options you want by default. A common .gizzmorc" opts.separator "simply contains:" opts.separator "" - opts.separator " host: localhost" + opts.separator " hosts: localhost" opts.separator " port: 7917" opts.separator "" opts.separator "Subcommands:" subcommands.keys.compact.sort.each do |sc| base = " #{sc}" @@ -303,39 +361,47 @@ opts.separator base end opts.separator "" opts.separator "" opts.separator "Global options:" - opts.on("-H", "--host=HOSTNAME", "HOSTNAME of remote thrift service") do |host| - global_options.host = host + opts.on("-H", "--hosts=HOST[,HOST,...]", "HOSTS of application servers") do |hosts| + global_options.hosts = hosts.split(",").map {|h| h.strip } end - opts.on("-P", "--port=PORT", "PORT of remote thrift service") do |port| + opts.on("-P", "--port=PORT", "PORT of remote manager service. default 7920") do |port| global_options.port = port.to_i end + opts.on("-I", "--injector=PORT", "PORT of remote job injector service. default 7921") do |port| + global_options.injector_port = port.to_i + end + + opts.on("-T", "--tables=TABLE[,TABLE,...]", "TABLE ids of forwardings to affect") do |tables| + global_options.tables = tables.split(",").map {|t| t.to_i } + end + opts.on("-F", "--framed", "use the thrift framed transport") do |framed| global_options.framed = true end opts.on("-r", "--retry=TIMES", "TIMES to retry the command") do |r| - global_options.retry = r + global_options.retry = r.to_i end opts.on("-t", "--timeout=SECONDS", "SECONDS to let the command run") do |r| - global_options.timeout = r + global_options.timeout = r.to_i end opts.on("--subtree", "Render in subtree mode") do global_options.render << "subtree" end opts.on("--info", "Render in info mode") do global_options.render << "info" end - opts.on("-D", "--dry-run", "") do |port| + opts.on("-D", "--dry-run", "") do global_options.dry = true end opts.on("-C", "--config=YAML_FILE", "YAML_FILE of option key/values") do |filename| load_config(global_options, filename) @@ -399,16 +465,16 @@ def custom_timeout(seconds) if seconds begin require "rubygems" require "system_timer" - SystemTimer.timeout_after(seconds.to_i) do + SystemTimer.timeout_after(seconds) do yield end rescue LoadError require "timeout" - Timeout.timeout(seconds.to_i) do + Timeout.timeout(seconds) do yield end end else yield @@ -425,11 +491,12 @@ STDERR.puts e.message STDERR.puts("=" * 80) end STDERR.puts subcommands[subcommand_name] exit 1 -rescue ThriftClient::Simple::ThriftException, Gizzard::Thrift::ShardException, Errno::ECONNREFUSED => e +rescue ThriftClient::Simple::ThriftException, Gizzard::GizzardException, Errno::ECONNREFUSED => e STDERR.puts e.message + STDERR.puts e.backtrace exit 1 rescue Errno::EPIPE # This is just us trying to puts into a closed stdout. For example, if you pipe into # head -1, then this script will keep running after head closes. We don't care, and # seeing the backtrace is annoying!