jackowayed-tyrantmanager 1.1.0
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/HISTORY.rdoc +34 -0
- data/LICENSE +13 -0
- data/README.rdoc +277 -0
- data/bin/tyrantmanager +10 -0
- data/data/config.rb +94 -0
- data/data/default_instance_config.rb +244 -0
- data/gemspec.rb +53 -0
- data/lib/tyrant_manager.rb +237 -0
- data/lib/tyrant_manager/cli.rb +152 -0
- data/lib/tyrant_manager/command.rb +119 -0
- data/lib/tyrant_manager/commands/create_instance.rb +27 -0
- data/lib/tyrant_manager/commands/list.rb +28 -0
- data/lib/tyrant_manager/commands/replication_status.rb +92 -0
- data/lib/tyrant_manager/commands/start.rb +32 -0
- data/lib/tyrant_manager/commands/stats.rb +24 -0
- data/lib/tyrant_manager/commands/status.rb +26 -0
- data/lib/tyrant_manager/commands/stop.rb +23 -0
- data/lib/tyrant_manager/log.rb +91 -0
- data/lib/tyrant_manager/paths.rb +77 -0
- data/lib/tyrant_manager/runner.rb +33 -0
- data/lib/tyrant_manager/tyrant_instance.rb +380 -0
- data/lib/tyrant_manager/version.rb +27 -0
- data/lib/tyrantmanager.rb +2 -0
- data/spec/command_spec.rb +37 -0
- data/spec/paths_spec.rb +57 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/tyrant_instance_spec.rb +106 -0
- data/spec/tyrant_manager_spec.rb +69 -0
- data/spec/version_spec.rb +16 -0
- data/tasks/announce.rake +43 -0
- data/tasks/config.rb +99 -0
- data/tasks/distribution.rake +38 -0
- data/tasks/documentation.rake +32 -0
- data/tasks/rspec.rake +29 -0
- data/tasks/rubyforge.rake +51 -0
- data/tasks/utils.rb +80 -0
- metadata +172 -0
data/gemspec.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'tyrant_manager/version'
|
3
|
+
require 'tasks/config'
|
4
|
+
|
5
|
+
TyrantManager::GEM_SPEC = Gem::Specification.new do |spec|
|
6
|
+
proj = Configuration.for('project')
|
7
|
+
spec.name = proj.name
|
8
|
+
spec.version = TyrantManager::VERSION
|
9
|
+
|
10
|
+
spec.author = proj.author
|
11
|
+
spec.email = proj.email
|
12
|
+
spec.homepage = proj.homepage
|
13
|
+
spec.summary = proj.summary
|
14
|
+
spec.description = proj.description
|
15
|
+
spec.platform = Gem::Platform::RUBY
|
16
|
+
|
17
|
+
|
18
|
+
pkg = Configuration.for('packaging')
|
19
|
+
spec.files = pkg.files.all
|
20
|
+
spec.executables = pkg.files.bin.collect { |b| File.basename(b) }
|
21
|
+
|
22
|
+
# add dependencies here
|
23
|
+
spec.add_dependency( "loquacious", "~> 1.3.0")
|
24
|
+
spec.add_dependency( "rufus-tokyo", "~> 1.0.0")
|
25
|
+
spec.add_dependency( "logging", "~> 1.1.4" )
|
26
|
+
spec.add_dependency( "main", "~> 2.8.4" )
|
27
|
+
|
28
|
+
# development dependencies
|
29
|
+
spec.add_development_dependency("configuration", ">= 0.0.5")
|
30
|
+
spec.add_development_dependency( "rake", "~> 0.8.3")
|
31
|
+
|
32
|
+
if ext_conf = Configuration.for_if_exist?("extension") then
|
33
|
+
spec.extensions << ext_conf.configs
|
34
|
+
spec.extensions.flatten!
|
35
|
+
end
|
36
|
+
|
37
|
+
if rdoc = Configuration.for_if_exist?('rdoc') then
|
38
|
+
spec.has_rdoc = true
|
39
|
+
spec.extra_rdoc_files = pkg.files.rdoc
|
40
|
+
spec.rdoc_options = rdoc.options + [ "--main" , rdoc.main_page ]
|
41
|
+
else
|
42
|
+
spec.has_rdoc = false
|
43
|
+
end
|
44
|
+
|
45
|
+
if test = Configuration.for_if_exist?('testing') then
|
46
|
+
spec.test_files = test.files
|
47
|
+
end
|
48
|
+
|
49
|
+
if rf = Configuration.for_if_exist?('rubyforge') then
|
50
|
+
spec.rubyforge_project = rf.project
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'loquacious'
|
8
|
+
require 'tyrant_manager/version'
|
9
|
+
require 'tyrant_manager/paths'
|
10
|
+
require 'tyrant_manager/log'
|
11
|
+
|
12
|
+
class TyrantManager
|
13
|
+
include TyrantManager::Paths
|
14
|
+
|
15
|
+
class Error < StandardError; end
|
16
|
+
|
17
|
+
class << TyrantManager
|
18
|
+
#
|
19
|
+
# The basename of the default config file
|
20
|
+
#
|
21
|
+
def config_file_basename
|
22
|
+
"config.rb"
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# The basename of the directory that holds the tyrant manager system
|
27
|
+
#
|
28
|
+
def basedir
|
29
|
+
"tyrant"
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# is the given directory a tyrant root directory. A tyrant root has a
|
34
|
+
# +config_file_basename+ file in the top level
|
35
|
+
#
|
36
|
+
def is_tyrant_root?( dir )
|
37
|
+
cfg = File.join( dir, config_file_basename )
|
38
|
+
return true if File.directory?( dir ) and File.exist?( cfg )
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Return the path of the tyrant dir if there is one relative to the current
|
44
|
+
# working directory. This means that there is a +config_file_basename+ in
|
45
|
+
# the current working directory.
|
46
|
+
#
|
47
|
+
# returns Dir.pwd if this is the case, nil otherwise
|
48
|
+
#
|
49
|
+
def cwd_default_directory
|
50
|
+
default_dir = Dir.pwd
|
51
|
+
return default_dir if is_tyrant_root?( default_dir )
|
52
|
+
return nil
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Return the path of the tyrant dir as it pertains to the
|
57
|
+
# TYRANT_MANAGER_HOME environment variable. If the directory is
|
58
|
+
# a tyrant root, then return that directory, otherwise return nil
|
59
|
+
#
|
60
|
+
def env_default_directory
|
61
|
+
default_dir = ENV['TYRANT_MANAGER_HOME']
|
62
|
+
return default_dir if default_dir and is_tyrant_root?( default_dir )
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Return the path of the tyrant dir as it pertains to the default global
|
68
|
+
# setting of 'lcoalstatedir' which is /opt/local/var, /var, or similar
|
69
|
+
#
|
70
|
+
def localstate_default_directory
|
71
|
+
default_dir = File.join( Config::CONFIG['localstatedir'], basedir )
|
72
|
+
return default_dir if is_tyrant_root?( default_dir )
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# The default tyrant directory. It is the first of these that matches:
|
78
|
+
#
|
79
|
+
# * current directory if there is a +config_file_basename+ file in the
|
80
|
+
# current dirctory
|
81
|
+
# * the value of the TYRANT_MANAGER_HOME environment variable
|
82
|
+
# * File.join( Config::CONFIG['localstatedir'], basedir )
|
83
|
+
#
|
84
|
+
def default_directory
|
85
|
+
defaults = [ self.cwd_default_directory,
|
86
|
+
self.env_default_directory,
|
87
|
+
self.localstate_default_directory ]
|
88
|
+
dd = nil
|
89
|
+
loop do
|
90
|
+
dd = defaults.shift
|
91
|
+
break if dd or defaults.empty?
|
92
|
+
end
|
93
|
+
raise Error, "No default_directory found" unless dd
|
94
|
+
return dd
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Return the default directory if it exists, otherwise fallback to .home_dir
|
99
|
+
#
|
100
|
+
def default_or_home_directory
|
101
|
+
hd = TyrantManager.home_dir
|
102
|
+
begin
|
103
|
+
hd = TyrantManager.default_directory
|
104
|
+
rescue => e
|
105
|
+
# yup, using home
|
106
|
+
end
|
107
|
+
return hd
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
#
|
112
|
+
# Setup the tyrant manager in the given directory. This means creating it
|
113
|
+
# if it does not exist.
|
114
|
+
#
|
115
|
+
def setup( dir = default_directory )
|
116
|
+
unless File.directory?( dir )
|
117
|
+
logger.info "Creating directory #{dir}"
|
118
|
+
FileUtils.mkdir_p( dir )
|
119
|
+
end
|
120
|
+
|
121
|
+
cfg = File.join( dir, config_file_basename )
|
122
|
+
|
123
|
+
unless File.exist?( cfg )
|
124
|
+
template = TyrantManager::Paths.data_path( config_file_basename )
|
125
|
+
logger.info "Creating default config file #{cfg}"
|
126
|
+
FileUtils.cp( template, dir )
|
127
|
+
end
|
128
|
+
|
129
|
+
%w[ instances log tmp ].each do |subdir|
|
130
|
+
subdir = File.join( dir, subdir )
|
131
|
+
unless File.directory?( subdir ) then
|
132
|
+
logger.info "Creating directory #{subdir}"
|
133
|
+
FileUtils.mkdir subdir
|
134
|
+
end
|
135
|
+
end
|
136
|
+
return TyrantManager.new( dir )
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Initialize the manager, which is nothing more than creating the instance and
|
142
|
+
# setting the home directory.
|
143
|
+
#
|
144
|
+
def initialize( directory = TyrantManager.default_directory )
|
145
|
+
self.home_dir = File.expand_path( directory )
|
146
|
+
if File.exist?( self.config_file ) then
|
147
|
+
configuration # force a load
|
148
|
+
else
|
149
|
+
raise Error, "#{home_dir} is not a valid archive. #{self.config_file} does not exist"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def logger
|
154
|
+
Logging::Logger[self]
|
155
|
+
end
|
156
|
+
|
157
|
+
#
|
158
|
+
# The configuration file for the manager
|
159
|
+
#
|
160
|
+
def config_file
|
161
|
+
@config_file ||= File.join( home_dir, TyrantManager.config_file_basename )
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# load the configuration
|
166
|
+
#
|
167
|
+
def configuration
|
168
|
+
unless @configuration
|
169
|
+
eval( IO.read( self.config_file ) )
|
170
|
+
@configuration = Loquacious::Configuration.for("manager")
|
171
|
+
end
|
172
|
+
return @configuration
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# Create a runner instance with the given options
|
177
|
+
#
|
178
|
+
def runner_for( options )
|
179
|
+
Runner.new( self, options )
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# Return the list of instances that the manager knows about
|
184
|
+
#
|
185
|
+
def instances
|
186
|
+
unless @instances then
|
187
|
+
candidates = [ self.instances_path ]
|
188
|
+
if configuration.instances then
|
189
|
+
candidates = configuration.instances
|
190
|
+
end
|
191
|
+
|
192
|
+
@instances = {}
|
193
|
+
while not candidates.empty? do
|
194
|
+
candidate = candidates.pop
|
195
|
+
cpath = append_to_home_if_not_absolute( candidate )
|
196
|
+
begin
|
197
|
+
t = TyrantInstance.new( cpath )
|
198
|
+
t.manager = self
|
199
|
+
@instances[t.name] = t
|
200
|
+
rescue TyrantManager::Error => e
|
201
|
+
if File.directory?( cpath ) then
|
202
|
+
Dir.glob( "#{cpath}/*" ).each do |epath|
|
203
|
+
if File.directory?( epath ) then
|
204
|
+
candidates.push epath
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end #while
|
210
|
+
end
|
211
|
+
return @instances
|
212
|
+
end
|
213
|
+
|
214
|
+
def each_instance
|
215
|
+
instances.keys.sort.each do |name|
|
216
|
+
yield instances[name]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
#
|
222
|
+
# take the given path, and if it is not an absolute path append it
|
223
|
+
# to the home directory of the instance.
|
224
|
+
def append_to_home_if_not_absolute( p )
|
225
|
+
path = Pathname.new( p )
|
226
|
+
unless path.absolute? then
|
227
|
+
path = Pathname.new( home_dir ) + path
|
228
|
+
end
|
229
|
+
return path.to_s
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
require 'tyrant_manager/cli'
|
236
|
+
require 'tyrant_manager/runner'
|
237
|
+
require 'tyrant_manager/tyrant_instance'
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'main'
|
2
|
+
require 'tyrant_manager'
|
3
|
+
|
4
|
+
class TyrantManager
|
5
|
+
Cli = Main.create {
|
6
|
+
author "Copyright 2009 (c) Jeremy Hinegardner"
|
7
|
+
version ::TyrantManager::VERSION
|
8
|
+
|
9
|
+
description <<-txt
|
10
|
+
The command line tool for managing tyrant instances.
|
11
|
+
|
12
|
+
Run 'tyrantmanager help modename' for more information
|
13
|
+
txt
|
14
|
+
|
15
|
+
run { help! }
|
16
|
+
|
17
|
+
mode( :setup ) {
|
18
|
+
description "Setup an tyrant manager location"
|
19
|
+
argument( :home ) {
|
20
|
+
description "The home directory of the tyrant manager"
|
21
|
+
required
|
22
|
+
default TyrantManager.default_or_home_directory
|
23
|
+
}
|
24
|
+
|
25
|
+
run {
|
26
|
+
TyrantManager::Log.init
|
27
|
+
TyrantManager.setup( params['home'].value )
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
mode( 'create-instance' ) {
|
32
|
+
description <<-txt
|
33
|
+
Create a new tyrant instance in the specified directory
|
34
|
+
txt
|
35
|
+
|
36
|
+
argument( 'instance-home' ) do
|
37
|
+
description <<-txt
|
38
|
+
The home directory of the tyrant instance. If this is a full path it
|
39
|
+
will be used. If it is a relative path, it will be relative to the
|
40
|
+
manager's 'instances' configuration parameter
|
41
|
+
txt
|
42
|
+
end
|
43
|
+
|
44
|
+
mixin :option_home
|
45
|
+
mixin :option_log_level
|
46
|
+
|
47
|
+
run { Cli.run_command_with_params( "create-instance", params ) }
|
48
|
+
}
|
49
|
+
|
50
|
+
mode( 'start' ) {
|
51
|
+
description "Start all the tyrants listed"
|
52
|
+
mixin :option_home
|
53
|
+
mixin :option_log_level
|
54
|
+
mixin :argument_instances
|
55
|
+
option( 'dry-run' ) {
|
56
|
+
description "Do not start, just show the commands"
|
57
|
+
default false
|
58
|
+
}
|
59
|
+
|
60
|
+
run { Cli.run_command_with_params( 'start', params ) }
|
61
|
+
}
|
62
|
+
|
63
|
+
|
64
|
+
mode( 'stop' ) {
|
65
|
+
description "Stop all the tyrants listed"
|
66
|
+
mixin :option_home
|
67
|
+
mixin :option_log_level
|
68
|
+
mixin :argument_instances
|
69
|
+
|
70
|
+
run { Cli.run_command_with_params( 'stop', params ) }
|
71
|
+
}
|
72
|
+
|
73
|
+
mode('replication-status') {
|
74
|
+
description "Describe the replication status of those servers using replication"
|
75
|
+
mixin :option_home
|
76
|
+
mixin :option_log_level
|
77
|
+
mixin :argument_instances
|
78
|
+
run { Cli.run_command_with_params( 'replication-status', params ) }
|
79
|
+
}
|
80
|
+
|
81
|
+
mode('process-status') {
|
82
|
+
description "Check the running status of all the tyrants listed"
|
83
|
+
mixin :option_home
|
84
|
+
mixin :option_log_level
|
85
|
+
|
86
|
+
mixin :argument_instances
|
87
|
+
|
88
|
+
run { Cli.run_command_with_params( 'process-status', params ) }
|
89
|
+
}
|
90
|
+
|
91
|
+
mode( 'stats' ) {
|
92
|
+
description "Dump the database statistics of each of the tyrants listed"
|
93
|
+
mixin :option_home
|
94
|
+
mixin :option_log_level
|
95
|
+
|
96
|
+
mixin :argument_instances
|
97
|
+
|
98
|
+
run { Cli.run_command_with_params( 'stats', params ) }
|
99
|
+
}
|
100
|
+
|
101
|
+
|
102
|
+
mode('list') {
|
103
|
+
description "list the instances and their home directories"
|
104
|
+
mixin :option_home
|
105
|
+
mixin :option_log_level
|
106
|
+
mixin :argument_instances
|
107
|
+
run { Cli.run_command_with_params( 'list', params ) }
|
108
|
+
}
|
109
|
+
|
110
|
+
#--- Mixins ---
|
111
|
+
mixin :option_home do
|
112
|
+
option( :home ) do
|
113
|
+
description "The home directory of the tyrant manager"
|
114
|
+
argument :required
|
115
|
+
validate { |v| ::File.directory?( v ) }
|
116
|
+
default TyrantManager.default_or_home_directory
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
mixin :option_log_level do
|
121
|
+
option('log-level') do
|
122
|
+
description "The verbosity of logging, one of [ #{::Logging::LNAMES.map {|l| l.downcase}.join(", ")} ]"
|
123
|
+
argument :required
|
124
|
+
validate { |l| %w[ debug info warn error fatal off ].include?( l.downcase ) }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
mixin :argument_instances do
|
129
|
+
argument('instances') do
|
130
|
+
description "A comman separated list of instance names the tyrant manager knows about"
|
131
|
+
argument :required
|
132
|
+
cast :list
|
133
|
+
default 'all'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
}
|
137
|
+
|
138
|
+
#
|
139
|
+
# Convert the Parameters::List that exists as the parameters from Main
|
140
|
+
#
|
141
|
+
def Cli.params_to_hash( params )
|
142
|
+
(hash = params.to_hash ).keys.each { |key| hash[key] = hash[key].value }
|
143
|
+
return hash
|
144
|
+
end
|
145
|
+
|
146
|
+
def Cli.run_command_with_params( command, params )
|
147
|
+
phash = Cli.params_to_hash( params )
|
148
|
+
TyrantManager::Log.init( phash )
|
149
|
+
tm = TyrantManager.new( phash.delete('home') )
|
150
|
+
tm.runner_for( phash ).run( command )
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'tyrant_manager'
|
2
|
+
class TyrantManager
|
3
|
+
#
|
4
|
+
# The Command is the base class for any class to be used as a command
|
5
|
+
#
|
6
|
+
# All commands run within the context of an existing TyrantManager location.
|
7
|
+
# Before the command starts the current working directory will be inside the
|
8
|
+
# tyrant manager's home directory.
|
9
|
+
#
|
10
|
+
# A command has a lifecyle of:
|
11
|
+
#
|
12
|
+
# * instantiation with a TyrantManager instance and an options hash
|
13
|
+
# * one call to before
|
14
|
+
# * one call to run
|
15
|
+
# * one call to after
|
16
|
+
#
|
17
|
+
# In case of an exception raised during the lifecycle, the +error+ method will
|
18
|
+
# be called. The +after+ method is called no matter what at the end of the
|
19
|
+
# lifecycle, even if an error has occurred.
|
20
|
+
#
|
21
|
+
class Command
|
22
|
+
def self.command_name
|
23
|
+
name.split("::").last.downcase
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :options
|
27
|
+
attr_reader :manager
|
28
|
+
|
29
|
+
#
|
30
|
+
# Instantiated and given the tyrant manager instance it is to operate
|
31
|
+
# through and a hash of options
|
32
|
+
#
|
33
|
+
def initialize( manager, opts = {} )
|
34
|
+
@manager = manager
|
35
|
+
@options = opts
|
36
|
+
end
|
37
|
+
|
38
|
+
def command_name
|
39
|
+
self.class.command_name
|
40
|
+
end
|
41
|
+
|
42
|
+
def logger
|
43
|
+
Logging::Logger[self]
|
44
|
+
end
|
45
|
+
|
46
|
+
#------------------------------------------------------------------
|
47
|
+
# lifecycle calls
|
48
|
+
#------------------------------------------------------------------
|
49
|
+
|
50
|
+
#
|
51
|
+
# call-seq:
|
52
|
+
# cmd.before
|
53
|
+
#
|
54
|
+
# called to allow the command to setup anything post initialization it
|
55
|
+
# needs to be able to +run+.
|
56
|
+
#
|
57
|
+
def before() nil ; end
|
58
|
+
|
59
|
+
#
|
60
|
+
# call-seq:
|
61
|
+
# cmd.run
|
62
|
+
#
|
63
|
+
# Yeah, this is where the work should be done.
|
64
|
+
#
|
65
|
+
def run()
|
66
|
+
raise NotImplementedError, "The #run method must be implemented"
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# call-seq:
|
71
|
+
# cmd.after
|
72
|
+
#
|
73
|
+
# called no matter what, after the execution of run() or error() if there was
|
74
|
+
# an exception. It is here to allow the cmd to do cleanup work.
|
75
|
+
#
|
76
|
+
def after() nil ; end
|
77
|
+
|
78
|
+
#
|
79
|
+
# call-seq:
|
80
|
+
# cmd.error( exception )
|
81
|
+
#
|
82
|
+
# called if there is an exception during the before() or after() calls. It
|
83
|
+
# is passed in the exception that was raised.
|
84
|
+
#
|
85
|
+
def error(exception) nil ; end
|
86
|
+
|
87
|
+
#------------------------------------------------------------------
|
88
|
+
# registration
|
89
|
+
#------------------------------------------------------------------
|
90
|
+
class CommandNotFoundError < ::TyrantManager::Error ; end
|
91
|
+
class << Command
|
92
|
+
def inherited( klass )
|
93
|
+
return unless klass.instance_of? Class
|
94
|
+
self.list << klass
|
95
|
+
end
|
96
|
+
|
97
|
+
def list
|
98
|
+
unless defined? @list
|
99
|
+
@list = Set.new
|
100
|
+
end
|
101
|
+
return @list
|
102
|
+
end
|
103
|
+
|
104
|
+
def find( command )
|
105
|
+
klass = list.find { |klass| klass.command_name == command }
|
106
|
+
return klass if klass
|
107
|
+
names = list.collect { |c| c.command_name }
|
108
|
+
raise CommandNotFoundError, "No command for '#{command}' was found. Known commands : #{names.join(",")}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
require 'tyrant_manager/commands/create_instance'
|
114
|
+
require 'tyrant_manager/commands/start'
|
115
|
+
require 'tyrant_manager/commands/stop'
|
116
|
+
require 'tyrant_manager/commands/status'
|
117
|
+
require 'tyrant_manager/commands/stats'
|
118
|
+
require 'tyrant_manager/commands/list'
|
119
|
+
require 'tyrant_manager/commands/replication_status'
|