- #!/usr/bin/env ruby
- require 'pathname'
- =begin
- Script to manage rails projects with unicorn server.
- Makes some assumptions:
- 1. Each project has corresponging system user.
- 2. Project deployed into $HOME/deploy with standard capistrano layout
- 3. Unicorn config lives in $HOME/deploy/current/config/unicorn.rb
- 4. Unicorn pid file lives in $HOME/deploy/shared/pids/unicorn.pid
- Tweak to your need by changing following configuration variables:
- RAILS_ENV - rails environment to run unicorns in
- BASE_DIR - homes for project users live here
- BUNDLE - full path to bundle command. By default script uses bundler installed with 'gem install' on debian system
- =end
- class ProjectRunningException < StandardError
- def initialize(name)
- super "Project #{name} already running"
- end
- end
- class Project
- RAILS_ENV = "production"
- BASE_DIR = "/srv/sites"
- RVM_SHELL = "/usr/local/rvm/bin/rvm-shell"
- BUNDLE = "/var/lib/gems/1.8/bin/bundle"
- @@projects = (Dir.entries(BASE_DIR) - ['.', '..']).select {|i|
- File.exists?(File.join(BASE_DIR, i, 'deploy', 'current', 'config', 'unicorn.rb'))
- }.sort
- attr_reader :name
- def initialize(name=nil)
- raise "No project specified" if name.nil?
- raise "Project not found. Use 'list' command for a list of project" unless @@projects.include? name
- @name = name
- @current_path = File.join(BASE_DIR, @name, 'deploy', 'current')
- @unicorn_conf = "#{@current_path}/config/unicorn.rb"
- @pid_file = File.join(BASE_DIR, @name, 'deploy', 'shared', 'pids', 'unicorn.pid')
- @user = name
- end
- def start
- #raise ProjectRunningException, @name if running?
- puts "Starting project #{@name}"
- rvm_ruby_string = Pathname(@current_path).join("config", "deploy.rb").open.grep(/rvm_ruby_string/).first
- if rvm_ruby_string
- ruby_version = rvm_ruby_string.split[2].gsub /['"]/, ''
- cmd = %Q(su #{@user} -c "#{RVM_SHELL} #{ruby_version} -c 'cd #{@current_path} && bundle exec unicorn_rails -c #{@unicorn_conf} -E #{RAILS_ENV} -D'")
- else
- cmd = %Q(su #{@user} -c "rvm-shell -c cd #{@current_path} && #{BUNDLE} exec unicorn_rails -c #{@unicorn_conf} -E #{RAILS_ENV} -D")
- end
- system cmd
- end
- def stop
- raise "Pid file does not exist for project #{@name}" unless File.exists? @pid_file
- pid = open(@pid_file).readline
- system("kill -QUIT #{pid}")
- end
- def running?
- system("ps ax | grep unicorn_rails | grep #{@name} | grep -v grep > /dev/null")
- end
- def stale?
- File.exists?(@pid_file) && !running?
- end
- def self.list
- @@projects.each do |name|
- project = new(name)
- prop = []
- if project.running?
- prop.push "[running]"
- elsif project.stale?
- prop.push "[stale]"
- end
- puts "#{project.name} #{prop.join ' '}"
- end
- end
- def self.start_all
- @@projects.each do |name|
- begin
- new(name).start
- rescue ProjectRunningException => e
- puts e
- next
- end
- end
- end
- end
- abort "Only root can run this program" if Process.uid != 0
- begin
- case ARGV.shift
- when "list"
- Project.list
- when "start"
- Project.new(ARGV.shift).start
- when "stop"
- Project.new(ARGV.shift).stop
- when "start_all"
- Project.start_all
- else
- raise
- end
- rescue Exception => e
- puts e unless e.message.empty?
- puts <<EOF
- Usage: #{__FILE__} list | start <project> | stop <project> | start_all
- EOF
- end