Class: CloudCrowd::CommandLine

Inherits:
Object
  • Object
show all
Defined in:
lib/cloud_crowd/command_line.rb

Constant Summary collapse

CONFIG_FILES =

Configuration files required for the ‘crowd` command to function.

['config.yml', 'config.ru', 'database.yml']
CC_ROOT =

Reference the absolute path to the root.

File.expand_path(File.dirname(__FILE__) + '/../..')
<<-EOS
CloudCrowd is a MapReduce-inspired Parallel Processing System for Ruby.

Wiki: http://wiki.github.com/documentcloud/cloud-crowd
Rdoc: http://rdoc.info/projects/documentcloud/cloud-crowd

Usage: crowd COMMAND OPTIONS

Commands:
  install       Install the CloudCrowd configuration files to the specified directory
  server        Start up the central server (requires a database)
  node          Start up a worker node (only one node per machine, please)
  console       Launch a CloudCrowd console, connected to the central database
  load_schema   Load the schema into the database specified by database.yml
  cleanup       Removes jobs that were finished over --days (7 by default) ago

  server -d [start | stop | restart]    Servers and nodes can be launched as
  node -d [start | stop | restart]      daemons, then stopped or restarted.

Options:
EOS

Instance Method Summary collapse

Constructor Details

#initializeCommandLine

Creating a CloudCrowd::CommandLine runs from the contents of ARGV.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/cloud_crowd/command_line.rb', line 37

def initialize
  parse_options
  command     = ARGV.shift
  subcommand  = ARGV.shift
  case command
  when 'console'      then run_console
  when 'server'       then run_server(subcommand)
  when 'node'         then run_node(subcommand)
  when 'load_schema'  then run_load_schema
  when 'install'      then run_install(subcommand)
  when 'cleanup'      then run_cleanup
  else                     usage
  end
end

Instance Method Details

#config_not_foundObject (private)

Exit with an explanation if the configuration files couldn’t be found.



229
230
231
232
# File 'lib/cloud_crowd/command_line.rb', line 229

def config_not_found
  puts "`crowd` can't find the CloudCrowd configuration directory. Please use `crowd -c path/to/config`, or run `crowd` from inside of the configuration directory itself."
  exit(1)
end

#connect_to_database(validate_schema) ⇒ Object (private)

Establish a connection to the central server’s database. Not all commands require this.



223
224
225
226
# File 'lib/cloud_crowd/command_line.rb', line 223

def connect_to_database(validate_schema)
  require 'cloud_crowd/models'
  CloudCrowd.configure_database("#{@options[:config_path]}/database.yml", validate_schema)
end

#ensure_configObject (private)

Check for configuration files, either in the current directory, or in the CLOUD_CROWD_CONFIG environment variable. Exit if they’re not found.



170
171
172
173
174
# File 'lib/cloud_crowd/command_line.rb', line 170

def ensure_config
  return if @config_found
  found = CONFIG_FILES.all? {|f| File.exists? "#{@options[:config_path]}/#{f}" }
  found ? @config_dir = true : config_not_found
end

#install_file(source, dest, is_dir = false) ⇒ Object (private)

Install a file and log the installation. If we’re overwriting a file, offer a chance to back out.



236
237
238
239
240
241
242
243
# File 'lib/cloud_crowd/command_line.rb', line 236

def install_file(source, dest, is_dir=false)
  if File.exists?(dest)
    print "#{dest} already exists. Overwrite it? (yes/no) "
    return unless ['y', 'yes', 'ok'].include? gets.chomp.downcase
  end
  is_dir ? FileUtils.cp_r(source, dest) : FileUtils.cp(source, dest)
  puts "installed #{dest}" unless ENV['RACK_ENV'] == 'test'
end

#load_codeObject (private)

Load in the CloudCrowd module code, dependencies, lib files and models. Not all commands require this.



215
216
217
218
219
# File 'lib/cloud_crowd/command_line.rb', line 215

def load_code
  ensure_config
  require "#{CC_ROOT}/lib/cloud-crowd"
  CloudCrowd.configure("#{@options[:config_path]}/config.yml")
end

#parse_optionsObject (private)

Parse all options for all commands. Valid options are: –config –port –environment –tag –daemonize –days.



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/cloud_crowd/command_line.rb', line 178

def parse_options
  @options = {
    :environment  => 'production',
    :config_path  => ENV['CLOUD_CROWD_CONFIG'] || '.',
    :daemonize    => false
  }
  @option_parser = OptionParser.new do |opts|
    opts.on('-c', '--config PATH', 'path to configuration directory') do |conf_path|
      @options[:config_path] = conf_path
    end
    opts.on('-p', '--port PORT', 'port number for server (central or node)') do |port_num|
      @options[:port] = port_num
    end
    opts.on('-e', '--environment ENV', 'server environment (defaults to production)') do |env|
      @options[:environment] = env
    end
    opts.on('-t', '--tag TAG', 'tag a node with a name') do |tag|
      @options[:tag] = tag
    end
    opts.on('-d', '--daemonize', 'run as a background daemon') do |daemonize|
      @options[:daemonize] = daemonize
    end
    opts.on('--days NUM_DAYS', 'grace period before cleanup (7 by default)') do |days|
      @options[:days] = days.to_i if days.match(/\A\d+\Z/)
    end
    opts.on_tail('-v', '--version', 'show version') do
      require "#{CC_ROOT}/lib/cloud-crowd"
      puts "CloudCrowd version #{VERSION}"
      exit
    end
  end
  @option_parser.banner = BANNER
  @option_parser.parse!(ARGV)
end

#restart_nodeObject

Restart the daemonized Node, if it exists.



128
129
130
131
132
# File 'lib/cloud_crowd/command_line.rb', line 128

def restart_node
  stop_node
  sleep 1
  start_node
end

#restart_serverObject

Restart the daemonized central server.



97
98
99
100
101
# File 'lib/cloud_crowd/command_line.rb', line 97

def restart_server
  stop_server
  sleep 1
  start_server
end

#run_cleanupObject

Clean up all Jobs in the CloudCrowd database older than –days old.



154
155
156
157
158
# File 'lib/cloud_crowd/command_line.rb', line 154

def run_cleanup
  load_code
  connect_to_database(true)
  Job.cleanup_all(:days => @options[:days])
end

#run_consoleObject

Spin up an IRB session with the CloudCrowd code loaded in, and a database connection established. The equivalent of Rails’ ‘script/console`.



54
55
56
57
58
59
60
61
62
63
# File 'lib/cloud_crowd/command_line.rb', line 54

def run_console
  require 'irb'
  require 'irb/completion'
  require 'pp'
  load_code
  connect_to_database true
  CloudCrowd::Server # Preload server to autoload classes.
  Object.send(:include, CloudCrowd)
  IRB.start
end

#run_install(install_path) ⇒ Object

Install the required CloudCrowd configuration files into the specified directory, or the current one.



143
144
145
146
147
148
149
150
151
# File 'lib/cloud_crowd/command_line.rb', line 143

def run_install(install_path)
  require 'fileutils'
  install_path ||= '.'
  FileUtils.mkdir_p install_path unless File.exists?(install_path)
  install_file "#{CC_ROOT}/config/config.example.yml", "#{install_path}/config.yml"
  install_file "#{CC_ROOT}/config/config.example.ru", "#{install_path}/config.ru"
  install_file "#{CC_ROOT}/config/database.example.yml", "#{install_path}/database.yml"
  install_file "#{CC_ROOT}/actions", "#{install_path}/actions", true
end

#run_load_schemaObject

Load in the database schema to the database specified in ‘database.yml’.



135
136
137
138
139
# File 'lib/cloud_crowd/command_line.rb', line 135

def run_load_schema
  load_code
  connect_to_database(false)
  require 'cloud_crowd/schema.rb'
end

#run_node(subcommand) ⇒ Object

‘crowd node` can either ’start’, ‘stop’, or ‘restart’.



104
105
106
107
108
109
110
111
112
# File 'lib/cloud_crowd/command_line.rb', line 104

def run_node(subcommand)
  load_code
  ENV['RACK_ENV'] = @options[:environment]
  case (subcommand || 'start')
  when 'start'    then start_node
  when 'stop'     then stop_node
  when 'restart'  then restart_node
  end
end

#run_server(subcommand) ⇒ Object

‘crowd server` can either ’start’, ‘stop’, or ‘restart’.



66
67
68
69
70
71
72
73
74
# File 'lib/cloud_crowd/command_line.rb', line 66

def run_server(subcommand)
  load_code
  subcommand ||= 'start'
  case subcommand
  when 'start'    then start_server
  when 'stop'     then stop_server
  when 'restart'  then restart_server
  end
end

#start_nodeObject

Launch a Node. Please only run a single node per machine. The Node process will be long-lived, although its workers will come and go.



116
117
118
119
120
# File 'lib/cloud_crowd/command_line.rb', line 116

def start_node
  @options[:port] ||= Node::DEFAULT_PORT
  puts "Starting CloudCrowd Node (#{VERSION}) on port #{@options[:port]}..."
  Node.new(@options)
end

#start_serverObject

Convenience command for quickly spinning up the central server. More sophisticated deployments, load-balancing across multiple app servers, should use the config.ru rackup file directly. This method will start a single Thin server.



80
81
82
83
84
85
86
87
88
89
# File 'lib/cloud_crowd/command_line.rb', line 80

def start_server
  port        = @options[:port] || 9173
  daemonize   = @options[:daemonize] ? '-d' : ''
  log_path    = CloudCrowd.log_path('server.log')
  pid_path    = CloudCrowd.pid_path('server.pid')
  rackup_path = File.expand_path("#{@options[:config_path]}/config.ru")
  FileUtils.mkdir_p(CloudCrowd.log_path) if @options[:daemonize] && !File.exists?(CloudCrowd.log_path)
  puts "Starting CloudCrowd Central Server (#{VERSION}) on port #{port}..."
  exec "thin -e #{@options[:environment]} -p #{port} #{daemonize} --tag cloud-crowd-server --log #{log_path} --pid #{pid_path} -R #{rackup_path} start"
end

#stop_nodeObject

If the daemonized Node is running, stop it.



123
124
125
# File 'lib/cloud_crowd/command_line.rb', line 123

def stop_node
  Thin::Server.kill CloudCrowd.pid_path('node.pid')
end

#stop_serverObject

Stop the daemonized central server, if it exists.



92
93
94
# File 'lib/cloud_crowd/command_line.rb', line 92

def stop_server
  Thin::Server.kill(CloudCrowd.pid_path('server.pid'), 0)
end

#usageObject

Print ‘crowd` usage.



161
162
163
# File 'lib/cloud_crowd/command_line.rb', line 161

def usage
  puts "\n#{@option_parser}\n"
end