flare-tools 0.1.4 → 0.4.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/Flare-tools.txt +0 -0
- data/History.txt +114 -2
- data/LICENSE +21 -0
- data/Manifest.txt +65 -8
- data/README.txt +356 -0
- data/Rakefile +90 -25
- data/Tutorial.txt +370 -0
- data/bin/flare-admin +6 -0
- data/bin/flare-argv0 +6 -0
- data/bin/flare-deploy +6 -0
- data/bin/flare-keychecker +6 -0
- data/bin/flare-part +6 -0
- data/bin/flare-ping +6 -0
- data/bin/flare-stats +4 -10
- data/bin/flare-zkadmin +6 -0
- data/lib/flare/net/connection.rb +98 -0
- data/lib/flare/test/cluster.rb +140 -0
- data/lib/flare/test/daemon.rb +144 -0
- data/lib/flare/test/node.rb +62 -0
- data/lib/flare/tools.rb +18 -16
- data/lib/flare/tools/cli.rb +32 -0
- data/lib/flare/tools/cli/activate.rb +106 -0
- data/lib/flare/tools/cli/balance.rb +83 -0
- data/lib/flare/tools/cli/cli_util.rb +77 -0
- data/lib/flare/tools/cli/deploy.rb +170 -0
- data/lib/flare/tools/cli/down.rb +85 -0
- data/lib/flare/tools/cli/dump.rb +219 -0
- data/lib/flare/tools/cli/dumpkey.rb +117 -0
- data/lib/flare/tools/cli/flare_admin.rb +81 -0
- data/lib/flare/tools/cli/flare_argv0.rb +60 -0
- data/lib/flare/tools/cli/flare_keychecker.rb +106 -0
- data/lib/flare/tools/cli/flare_zkadmin.rb +226 -0
- data/lib/flare/tools/cli/index.rb +54 -0
- data/lib/flare/tools/cli/list.rb +93 -0
- data/lib/flare/tools/cli/master.rb +143 -0
- data/lib/flare/tools/cli/part.rb +100 -0
- data/lib/flare/tools/cli/ping.rb +81 -0
- data/lib/flare/tools/cli/reconstruct.rb +164 -0
- data/lib/flare/tools/cli/remove.rb +119 -0
- data/lib/flare/tools/cli/restore.rb +180 -0
- data/lib/flare/tools/cli/slave.rb +125 -0
- data/lib/flare/tools/cli/stats.rb +229 -122
- data/lib/flare/tools/cli/sub_command.rb +73 -0
- data/lib/flare/tools/cli/summary.rb +97 -0
- data/lib/flare/tools/cli/threads.rb +78 -0
- data/lib/flare/tools/cli/verify.rb +202 -0
- data/lib/flare/tools/client.rb +267 -0
- data/lib/flare/tools/cluster.rb +319 -0
- data/lib/flare/tools/common.rb +196 -0
- data/lib/flare/tools/index_server.rb +51 -0
- data/lib/flare/tools/node.rb +162 -0
- data/lib/flare/tools/stats.rb +75 -0
- data/lib/flare/tools/zk_util.rb +28 -0
- data/lib/flare/util.rb +34 -0
- data/lib/flare/util/bwlimit.rb +132 -0
- data/lib/flare/util/command_line.rb +79 -0
- data/lib/flare/util/conf.rb +71 -0
- data/lib/flare/util/constant.rb +25 -0
- data/lib/flare/util/conversion.rb +26 -0
- data/lib/flare/util/default_logger.rb +52 -0
- data/lib/flare/util/exception.rb +19 -0
- data/lib/flare/util/filesystem.rb +30 -0
- data/lib/flare/util/flared_conf.rb +33 -0
- data/lib/flare/util/flarei_conf.rb +32 -0
- data/lib/flare/util/hash_function.rb +32 -0
- data/lib/flare/util/interruption.rb +70 -0
- data/lib/flare/util/key_resolver.rb +67 -0
- data/lib/flare/util/log4r_logger.rb +79 -0
- data/lib/flare/util/logger.rb +40 -0
- data/lib/flare/util/logging.rb +84 -0
- data/lib/flare/util/result.rb +53 -0
- data/test/test/experimental/cache_test.rb +113 -0
- data/test/test/experimental/key_distribution_test.rb +38 -0
- data/test/test/experimental/keychecker_test.rb +60 -0
- data/test/test/experimental/list_test.rb +108 -0
- data/test/test/extra/replication_test.rb +184 -0
- data/test/test/integration/cli_test.rb +348 -0
- data/test/test/integration/dump_expired_test.rb +103 -0
- data/test/test/integration/dump_test.rb +128 -0
- data/test/test/integration/index_server_test.rb +35 -0
- data/test/test/integration/node_test.rb +78 -0
- data/test/test/integration/partition_test.rb +235 -0
- data/test/test/integration/proxy_test.rb +54 -0
- data/test/test/integration/stats_test.rb +79 -0
- data/test/test/system/flare_admin_test.rb +191 -0
- data/test/test/unit/bwlimit_test.rb +52 -0
- data/test/test/unit/cluster_test.rb +96 -0
- data/test/test/unit/daemon_test.rb +30 -0
- data/test/test/unit/logger_test.rb +46 -0
- data/test/test/unit/tools_test.rb +25 -0
- data/test/test/unit/util_test.rb +70 -0
- metadata +239 -84
- data/README.rdoc +0 -83
- data/bin/flare-partition-setting +0 -12
- data/lib/flare/tools/cli/partition_setting.rb +0 -86
- data/lib/flare/tools/core.rb +0 -189
- data/lib/flare/tools/logger.rb +0 -31
- data/test/test_flare-tools.rb +0 -11
- data/test/test_helper.rb +0 -3
@@ -0,0 +1,85 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
# Authors:: Kiyoshi Ikehara <kiyoshi.ikehara@gree.net>
|
3
|
+
# Copyright:: Copyright (C) GREE, Inc. 2011.
|
4
|
+
# License:: MIT-style
|
5
|
+
|
6
|
+
require 'flare/tools/stats'
|
7
|
+
require 'flare/tools/node'
|
8
|
+
require 'flare/tools/index_server'
|
9
|
+
require 'flare/tools/common'
|
10
|
+
require 'flare/tools/cluster'
|
11
|
+
require 'flare/util/conversion'
|
12
|
+
require 'flare/util/constant'
|
13
|
+
require 'flare/tools/cli/sub_command'
|
14
|
+
|
15
|
+
module Flare
|
16
|
+
module Tools
|
17
|
+
module Cli
|
18
|
+
|
19
|
+
class Down < SubCommand
|
20
|
+
include Flare::Util::Conversion
|
21
|
+
include Flare::Util::Constant
|
22
|
+
include Flare::Tools::Common
|
23
|
+
|
24
|
+
myname :down
|
25
|
+
desc "turn down nodes and move them to proxy state."
|
26
|
+
usage "down [hostname:port] ..."
|
27
|
+
|
28
|
+
def setup(opt)
|
29
|
+
opt.on('--force', "commit changes without confirmation") {@force = true}
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
@force = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute(config, *args)
|
38
|
+
return S_NG if args.size < 1
|
39
|
+
|
40
|
+
hosts = args.map {|x| x.split(':')}
|
41
|
+
hosts.each do |x|
|
42
|
+
if x.size != 2
|
43
|
+
puts "invalid argument '#{x.join(':')}'."
|
44
|
+
return S_NG
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Flare::Tools::IndexServer.open(config[:index_server_hostname], config[:index_server_port], config[:timeout]) do |s|
|
49
|
+
cluster = Flare::Tools::Cluster.new(s.host, s.port, s.stats_nodes)
|
50
|
+
|
51
|
+
hosts.each do |hostname,port|
|
52
|
+
down = 'down'
|
53
|
+
nodekey = nodekey_of hostname, port
|
54
|
+
ipaddr = address_of_hostname(hostname)
|
55
|
+
|
56
|
+
unless cluster.has_nodekey? nodekey
|
57
|
+
error "invalid 'hostname:port' pair: #{nodekey}"
|
58
|
+
return S_NG
|
59
|
+
end
|
60
|
+
|
61
|
+
node = cluster.node_stat(nodekey)
|
62
|
+
|
63
|
+
exec = @force
|
64
|
+
if exec
|
65
|
+
elsif node['state'] == down
|
66
|
+
puts "#{ipaddr}:#{port} is already down."
|
67
|
+
else
|
68
|
+
STDERR.print "turning node down (node=#{ipaddr}:#{port}, state=#{node['state']} -> #{down}) (y/n): "
|
69
|
+
exec = interruptible {(gets.chomp.upcase == "Y")}
|
70
|
+
end
|
71
|
+
if exec
|
72
|
+
s.set_state(hostname, port, down) unless config[:dry_run]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
puts string_of_nodelist(s.stats_nodes, hosts.map {|x| "#{x[0]}:#{x[1]}"})
|
77
|
+
end
|
78
|
+
|
79
|
+
S_OK
|
80
|
+
end # execute()
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,219 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
# Authors:: Kiyoshi Ikehara <kiyoshi.ikehara@gree.net>
|
3
|
+
# Copyright:: Copyright (C) GREE, Inc. 2011.
|
4
|
+
# License:: MIT-style
|
5
|
+
|
6
|
+
require 'flare/tools/node'
|
7
|
+
require 'flare/tools/index_server'
|
8
|
+
require 'flare/tools/common'
|
9
|
+
require 'flare/util/conversion'
|
10
|
+
require 'flare/util/constant'
|
11
|
+
require 'flare/util/bwlimit'
|
12
|
+
require 'flare/tools/cli/sub_command'
|
13
|
+
require 'csv'
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'tokyocabinet'
|
17
|
+
rescue LoadError => e
|
18
|
+
end
|
19
|
+
|
20
|
+
module Flare
|
21
|
+
module Tools
|
22
|
+
module Cli
|
23
|
+
|
24
|
+
class Dump < SubCommand
|
25
|
+
|
26
|
+
class Dumper
|
27
|
+
attr_reader :name
|
28
|
+
def write data, key, flag, len, version, expire
|
29
|
+
raise "internal error"
|
30
|
+
end
|
31
|
+
def close
|
32
|
+
raise "internal error"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class DefaultDumper < Dumper
|
37
|
+
def self.myname
|
38
|
+
"default"
|
39
|
+
end
|
40
|
+
def initialize filepath_or_writable
|
41
|
+
@output = if filepath_or_writable.kind_of?(String)
|
42
|
+
open(filepath_or_writable, 'w')
|
43
|
+
else
|
44
|
+
filepath_or_writable
|
45
|
+
end
|
46
|
+
end
|
47
|
+
def write data, key, flag, len, version, expire
|
48
|
+
@output.puts "#{key} #{flag} #{len} #{version} #{expire} '#{data}'"
|
49
|
+
end
|
50
|
+
def close
|
51
|
+
@output.close unless @output == STDOUT || @output == STDERR
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class CsvDumper < Dumper
|
56
|
+
def self.myname
|
57
|
+
"csv"
|
58
|
+
end
|
59
|
+
def initialize filepath_or_writable
|
60
|
+
@output = if filepath_or_writable.kind_of?(String)
|
61
|
+
open(filepath_or_writable, 'w')
|
62
|
+
else
|
63
|
+
filepath_or_writable
|
64
|
+
end
|
65
|
+
@output.puts "# key, flag, len, version, expire, data"
|
66
|
+
@writer = CSV::Writer.generate(@output, ',')
|
67
|
+
end
|
68
|
+
def write data, key, flag, len, version, expire
|
69
|
+
@writer << [key, flag, len, version, expire, data]
|
70
|
+
end
|
71
|
+
def close
|
72
|
+
@output.close unless @output == STDOUT || @output == STDERR
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class TchDumper < Dumper
|
77
|
+
def self.myname
|
78
|
+
"tch"
|
79
|
+
end
|
80
|
+
def initialize filepath
|
81
|
+
raise "output file not specified." if filepath.nil?
|
82
|
+
raise "#{filepath} isn't a path." unless filepath.kind_of?(String)
|
83
|
+
@hdb = TokyoCabinet::HDB.new
|
84
|
+
@hdb.open(filepath, TokyoCabinet::HDB::OCREAT|TokyoCabinet::HDB::OWRITER)
|
85
|
+
end
|
86
|
+
def write data, key, flag, size, version, expire
|
87
|
+
# uint32_t flag -> L // uint32_t
|
88
|
+
# time_t expire -> Q // unsigned long
|
89
|
+
# uint64_t size -> Q // uint64_t
|
90
|
+
# uint64_t version -> Q // uint64_t
|
91
|
+
# uint32_t option -> L // uint32_t
|
92
|
+
value = [flag, expire, size, version].pack("LQQQ")+data
|
93
|
+
@hdb.put(key, value)
|
94
|
+
end
|
95
|
+
def close
|
96
|
+
@hdb.close
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Iterators = [DefaultDumper, CsvDumper]
|
101
|
+
Iterators << TchDumper if defined? TokyoCabinet
|
102
|
+
Formats = Iterators.map {|n| n.myname}
|
103
|
+
SizeOfByte = 8
|
104
|
+
|
105
|
+
include Flare::Util::Conversion
|
106
|
+
include Flare::Util::Constant
|
107
|
+
include Flare::Tools::Common
|
108
|
+
|
109
|
+
myname :dump
|
110
|
+
desc "dump data from nodes. (experimental)"
|
111
|
+
usage "dump [hostname:port] ..."
|
112
|
+
|
113
|
+
def setup(opt)
|
114
|
+
opt.on('-o', '--output=FILE', "output to file") {|v| @output = v}
|
115
|
+
opt.on('-f', '--format=FORMAT', "specify output format [#{Formats.join(',')}]") {|v| @format = v}
|
116
|
+
opt.on( '--bwlimit=BANDWIDTH', "specify bandwidth limit (bps)") {|v|
|
117
|
+
@bwlimit = Flare::Util::Bwlimit.bps(v)
|
118
|
+
}
|
119
|
+
opt.on('--all', "dump from all master nodes") {|v| @all = true}
|
120
|
+
opt.on('--raw', "raw dump mode (for debugging)") {|v| @raw = true}
|
121
|
+
end
|
122
|
+
|
123
|
+
def initialize
|
124
|
+
super
|
125
|
+
@output = nil
|
126
|
+
@format = nil
|
127
|
+
@bwlimit = 0
|
128
|
+
@all = false
|
129
|
+
@raw = false
|
130
|
+
@partition_size = 1
|
131
|
+
end
|
132
|
+
|
133
|
+
def execute(config, *args)
|
134
|
+
STDERR.puts "please install tokyocabinet via gem command." unless defined? TokyoCabinet
|
135
|
+
|
136
|
+
cluster = nil
|
137
|
+
Flare::Tools::IndexServer.open(config[:index_server_hostname], config[:index_server_port], config[:timeout]) do |s|
|
138
|
+
cluster = Flare::Tools::Cluster.new(s.host, s.port, s.stats_nodes)
|
139
|
+
end
|
140
|
+
return S_NG if cluster.nil?
|
141
|
+
|
142
|
+
partition_size = cluster.partition_size
|
143
|
+
|
144
|
+
if @all
|
145
|
+
if args.size > 0
|
146
|
+
STDERR.puts "don't specify any nodes with --all option."
|
147
|
+
return S_NG
|
148
|
+
else
|
149
|
+
args = cluster.master_nodekeys
|
150
|
+
end
|
151
|
+
else
|
152
|
+
if args.size == 0
|
153
|
+
STDERR.puts "please specify --all option to get complete dump."
|
154
|
+
return S_NG
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
unless Formats.include?(@format)
|
159
|
+
STDERR.puts "unknown format: #{@format}"
|
160
|
+
return S_NG
|
161
|
+
end
|
162
|
+
|
163
|
+
hosts = args.map {|x| x.split(':')}
|
164
|
+
hosts.each do |x|
|
165
|
+
if x.size == 2
|
166
|
+
x << cluster.partition_of_nodename("#{x[0]}:#{x[1]}")
|
167
|
+
elsif x.size == 4
|
168
|
+
if x[3] =~ /^\d+$/
|
169
|
+
STDERR.puts "invalid partition number '#{x.join(':')}'."
|
170
|
+
x[3] = x[3].to_i
|
171
|
+
else
|
172
|
+
STDERR.puts "invalid partition number '#{x.join(':')}'."
|
173
|
+
return S_NG
|
174
|
+
end
|
175
|
+
else
|
176
|
+
STDERR.puts "invalid argument '#{x.join(':')}'."
|
177
|
+
return S_NG
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
dumper = case @format
|
182
|
+
when CsvDumper.myname
|
183
|
+
CsvDumper.new(@output || STDOUT)
|
184
|
+
when TchDumper.myname
|
185
|
+
TchDumper.new @output
|
186
|
+
else
|
187
|
+
DefaultDumper.new(@output || STDOUT)
|
188
|
+
end
|
189
|
+
|
190
|
+
hosts.each do |hostname,port,partition|
|
191
|
+
Flare::Tools::Node.open(hostname, port.to_i, config[:timeout], 0, @bwlimit) do |n|
|
192
|
+
interval = 0
|
193
|
+
part, partsize = if @raw
|
194
|
+
[0, 1]
|
195
|
+
else
|
196
|
+
[partition, partition_size]
|
197
|
+
end
|
198
|
+
bwlimit = @bwlimit/1024/SizeOfByte
|
199
|
+
count = 0
|
200
|
+
STDERR.print "dumping from #{hostname}:#{port}::#{part} of #{partsize} partitions ... "
|
201
|
+
n.dump(interval, part, partsize, bwlimit) do |data, key, flag, len, version, expire|
|
202
|
+
dumper.write data, key, flag, len, version, expire
|
203
|
+
count += 1
|
204
|
+
false
|
205
|
+
end
|
206
|
+
STDERR.puts "#{count}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
dumper.close
|
211
|
+
|
212
|
+
S_OK
|
213
|
+
end # execute()
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
# Authors:: Kiyoshi Ikehara <kiyoshi.ikehara@gree.net>
|
3
|
+
# Copyright:: Copyright (C) GREE, Inc. 2011.
|
4
|
+
# License:: MIT-style
|
5
|
+
|
6
|
+
require 'flare/tools/node'
|
7
|
+
require 'flare/tools/index_server'
|
8
|
+
require 'flare/tools/common'
|
9
|
+
require 'flare/util/conversion'
|
10
|
+
require 'flare/util/constant'
|
11
|
+
require 'flare/util/bwlimit'
|
12
|
+
require 'flare/tools/cli/sub_command'
|
13
|
+
|
14
|
+
require 'csv'
|
15
|
+
|
16
|
+
module Flare
|
17
|
+
module Tools
|
18
|
+
module Cli
|
19
|
+
|
20
|
+
class Dumpkey < SubCommand
|
21
|
+
include Flare::Util::Conversion
|
22
|
+
include Flare::Util::Constant
|
23
|
+
include Flare::Tools::Common
|
24
|
+
|
25
|
+
myname :dumpkey
|
26
|
+
desc "dump key from nodes."
|
27
|
+
usage "dumpkey [hostname:port] ..."
|
28
|
+
|
29
|
+
def setup(opt)
|
30
|
+
opt.on('-o', '--output=FILE', "output to file" ) {|v| @output = v}
|
31
|
+
opt.on('-f', '--format=FORMAT', "output format [csv]" ) {|v| @format = v}
|
32
|
+
opt.on('-p', '--partition=NUMBER', "partition number" ) {|v| @part = v.to_i if v.to_i >= 0}
|
33
|
+
opt.on('-s', '--partition-size=SIZE', "partition size" ) {|v| @partsize = v.to_i if v.to_i > 0}
|
34
|
+
opt.on( '--bwlimit=BANDWIDTH', "bandwidth limit (bps)" ) {|v| @bwlimit = v if v.to_i > 0}
|
35
|
+
opt.on( '--all', "dump form all partitions") {@all = true}
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
super
|
40
|
+
@output = nil
|
41
|
+
@format = nil
|
42
|
+
@part = nil
|
43
|
+
@partsize = nil
|
44
|
+
@bwlimit = nil
|
45
|
+
@all = false
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute(config, *args)
|
49
|
+
cluster = nil
|
50
|
+
Flare::Tools::IndexServer.open(config[:index_server_hostname], config[:index_server_port], config[:timeout]) do |s|
|
51
|
+
cluster = Flare::Tools::Cluster.new(s.host, s.port, s.stats_nodes)
|
52
|
+
end
|
53
|
+
return S_NG if cluster.nil?
|
54
|
+
|
55
|
+
if @all
|
56
|
+
unless args.empty?
|
57
|
+
STDERR.puts "don't specify any nodes with --all option."
|
58
|
+
return S_NG
|
59
|
+
else
|
60
|
+
args = cluster.master_nodekeys
|
61
|
+
end
|
62
|
+
else
|
63
|
+
if args.empty?
|
64
|
+
STDERR.puts "please specify --all option to get complete dump."
|
65
|
+
return S_NG
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
unless @format.nil?
|
70
|
+
unless ["csv"].include? @format
|
71
|
+
puts "unknown format: #{@format}"
|
72
|
+
return S_NG
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
hosts = args.map {|x| x.split(':')}
|
77
|
+
hosts.each do |x|
|
78
|
+
if x.size != 2
|
79
|
+
puts "invalid argument '#{x.join(':')}'."
|
80
|
+
return S_NG
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
hosts.each do |hostname,port|
|
85
|
+
Flare::Tools::Node.open(hostname, port.to_i, config[:timeout], @bwlimit, @bwlimit) do |n|
|
86
|
+
output = STDOUT
|
87
|
+
unless @output.nil?
|
88
|
+
output = File.open(@output, "w")
|
89
|
+
end
|
90
|
+
case @format
|
91
|
+
when "csv"
|
92
|
+
writer = CSV::Writer.generate(output)
|
93
|
+
output.puts "# key"
|
94
|
+
end
|
95
|
+
interruptible {
|
96
|
+
n.dumpkey(@part, @partsize) do |key|
|
97
|
+
case @format
|
98
|
+
when "csv"
|
99
|
+
writer << [key]
|
100
|
+
else
|
101
|
+
output.puts "#{key}"
|
102
|
+
end
|
103
|
+
false
|
104
|
+
end
|
105
|
+
}
|
106
|
+
output.close if output != STDOUT
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
S_OK
|
111
|
+
end # execute()
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# -*- coding: utf-8; -*-
|
2
|
+
# Authors:: Kiyoshi Ikehara <kiyoshi.ikehara@gree.net>
|
3
|
+
# Copyright:: Copyright (C) GREE, Inc. 2011.
|
4
|
+
# License:: MIT-style
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'flare/util/logging'
|
8
|
+
require 'flare/util/constant'
|
9
|
+
require 'flare/tools'
|
10
|
+
require 'flare/tools/cli'
|
11
|
+
require 'flare/tools/cli/cli_util'
|
12
|
+
|
13
|
+
require 'flare/util/command_line'
|
14
|
+
|
15
|
+
Version = Flare::Tools::VERSION
|
16
|
+
include Flare::Util::Logging
|
17
|
+
include Flare::Util::Constant
|
18
|
+
include Flare::Tools::Cli::CliUtil
|
19
|
+
Cli = Flare::Tools::Cli
|
20
|
+
|
21
|
+
index_server_hostname = nil
|
22
|
+
index_server_port = nil
|
23
|
+
timeout = DefaultTimeout
|
24
|
+
dry_run = false
|
25
|
+
cluster = nil
|
26
|
+
scname = ''
|
27
|
+
subc = nil
|
28
|
+
|
29
|
+
scclasses = [Cli::List, Cli::Balance, Cli::Down, Cli::Slave, Cli::Reconstruct, Cli::Master, Cli::Threads, Cli::Ping, Cli::Remove, Cli::Index, Cli::Activate, Cli::Dump, Cli::Dumpkey, Cli::Verify, Cli::Stats, Cli::Restore, Cli::Summary]
|
30
|
+
unsupported = [Cli::Deploy]
|
31
|
+
scclasses.concat unsupported
|
32
|
+
|
33
|
+
subcommands = Hash[*scclasses.map {|x| [x.to_sym, x]}.flatten]
|
34
|
+
|
35
|
+
setup do |opt|
|
36
|
+
opt.banner = "#{Flare::Tools::TITLE}\nUsage: flare-admin [subcommand] [options] [arguments]"
|
37
|
+
opt.on("-n", '--dry-run', "dry run") {dry_run = true}
|
38
|
+
opt.on("-i HOSTNAME", '--index-server=HOSTNAME', "index server hostname(default:#{DefaultIndexServerName})") {|v| index_server_hostname = v}
|
39
|
+
opt.on("-p PORT", '--index-server-port=PORT', "index server port(default:#{DefaultIndexServerPort})") {|v| index_server_port = v.to_i}
|
40
|
+
opt.on( '--log-file=LOGFILE', "output log to LOGFILE") {|v| Flare::Util::Logging.set_logger(v)}
|
41
|
+
opt.on( '--cluster=NAME', "specify a cluster name") {|v| cluster = v}
|
42
|
+
opt.on( '--timeout=SECOND', "specify timeout") {|v| timeout = v.to_i}
|
43
|
+
|
44
|
+
preparsed = opt.order(ARGV)
|
45
|
+
scname = preparsed.shift.to_sym if preparsed.size > 0
|
46
|
+
|
47
|
+
if subcommands.include?(scname)
|
48
|
+
subc = subcommands[scname].new
|
49
|
+
opt.separator("#{scname} subcommand:")
|
50
|
+
subc.setup(opt)
|
51
|
+
else
|
52
|
+
error "unknown subcommand '#{scname}'" unless scname == ''
|
53
|
+
opt.separator("subcommands:")
|
54
|
+
puts opt.help
|
55
|
+
subcommands.each do |k,v|
|
56
|
+
next if unsupported.include?(v)
|
57
|
+
o = OptionParser.new
|
58
|
+
o.banner = "[#{k.to_s}] "+v.desc
|
59
|
+
o.separator(" Usage: flare-admin "+v.usage)
|
60
|
+
v.new.setup(o)
|
61
|
+
puts o.help
|
62
|
+
end
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
status = execute do |args|
|
68
|
+
command = args.shift
|
69
|
+
ihostname, iport = get_index_server_from_nodekeys(args) ||
|
70
|
+
get_index_server_name_and_port(index_server_hostname, index_server_port)
|
71
|
+
ihostname, iport = get_index_server_from_cluster(cluster) unless cluster.nil?
|
72
|
+
subc.execute({ :command => command,
|
73
|
+
:index_server_hostname => ihostname,
|
74
|
+
:index_server_port => iport,
|
75
|
+
:dry_run => dry_run,
|
76
|
+
:timeout => timeout,
|
77
|
+
:cluster => cluster },
|
78
|
+
*args) if subc
|
79
|
+
end
|
80
|
+
|
81
|
+
exit status
|