module TorqueBox::DeployUtils

Public Class Methods

archive_name(root = Dir.pwd) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 107
def archive_name(root = Dir.pwd)
  normalize_archive_name( File.basename( root || Dir.pwd ) )
end
basic_deployment_descriptor(options = {}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 291
def basic_deployment_descriptor(options = {})
  env = options[:env] || options['env']
  env ||= defined?(RACK_ENV) ? RACK_ENV : ENV['RACK_ENV']
  env ||= defined?(::Rails) && Rails.respond_to?(:env) ? ::Rails.env : ENV['RAILS_ENV']

  root = options[:root] || options['root'] || Dir.pwd
  context_path = options[:context_path] || options['context_path']

  d = {}
  d['application'] = {}
  d['application']['root'] = root
  d['environment'] = {}
  d['environment']['RACK_ENV'] = env.to_s if env

  if context_path
    d['web'] = {}
    d['web']['context'] = context_path
  end

  d
end
check_opt_torquebox() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 120
def check_opt_torquebox
  raise "TorqueBox not installed in #{opt_torquebox}" unless ( File.exist?( opt_torquebox ) )
  puts "TorqueBox install OK: #{opt_torquebox}"
end
check_server() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 115
def check_server
  raise "#{jboss_home} doesn't appear to be a valid TorqueBox install" unless File.exist?( torquebox_modules_dir )
  puts "TorqueBox installation appears OK"
end
cluster_config_file() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 78
def cluster_config_file
  eap? ? "torquebox-full-ha.xml" : "standalone-ha.xml"
end
config_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 70
def config_dir
  File.join("#{server_dir}","configuration")
end
create_archive(opts = {}) click to toggle source

name: (string) what to call the resulting knob file app_dir: (string) where the application to be packaged is dest_dir: (string) where to put the resulting knob file exclude: (string) string or regex of files to exclude from the archive precompile_assets: (boolean) whether or not to precompile assets. this is rails-specific. package_gems: (boolean) whether or not to install all bundle gems to vendor/bundle (this

is rather convenient as it means that you don't have to run bundle
install on your production servers)

package_without: (array) all the bundler groups to run bundle install without (cuts down

on package size by snipping out potentially inappropriate
dependencies for a production environment).
# File lib/torquebox/deploy_utils.rb, line 194
def create_archive(opts = {})
  archive = normalize_archive_name( find_option( opts, 'name' ) || archive_name )
  app_dir = find_option( opts, 'app_dir' ) || Dir.pwd
  dest_dir = find_option( opts, 'dest_dir' ) || Dir.pwd
  excludes = find_option( opts, 'exclude' ) || ""
  should_precompile_assets = find_option( opts, 'precompile_assets' ) == true
  should_package_gems = find_option( opts, 'package_gems' ) == true
  package_without = find_option( opts, 'package_without' ) || Array.new

  if should_precompile_assets
    precompile_assets( app_dir )
    raise 'Error precompiling assets' unless $? == 0
  end

  archive_path = File.join( dest_dir, archive )
  archive_proc = lambda { create_knob_archive( app_dir, archive_path, excludes ) }

  if should_package_gems
    package_gems( app_dir, package_without ) {
      raise 'Error packaging gems' unless $? == 0
      archive_proc.call
    }
  else
    archive_proc.call
  end

  archive_path
end
create_knob_archive(app_dir, archive_path, excludes) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 260
def create_knob_archive(app_dir, archive_path, excludes)
  default_skip_files = %w{ ^log/ ^tmp/ ^test/ ^spec/ ^[^/]*\.knob$ vendor/.*cache/.*\.gem$ }
  opts_skip_files = excludes.split( /,/ ).map { |r| "^[^/]*#{r}" }
  skip_files = default_skip_files + opts_skip_files

  Dir.chdir( app_dir ) do
    include_files = []
    Dir[ "**/**", ".bundle/**/**", "**/.*manifest*" ].each do |entry|
      unless File.directory?( entry ) || skip_files.any? { |regex| entry.match( regex ) }
        include_files << '"' + entry.to_s + '"'
      end
    end

    includes = Tempfile.new( "include-files" )
    includes.write( include_files.join( "\n" ) )
    includes.flush

    cmd = "jar cvf \"#{archive_path}\" @#{includes.path}"

    run_command( cmd )
    includes.close( true )
  end
end
deploy_archive(opts = {}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 324
def deploy_archive(opts = {})
  name = normalize_archive_name( find_option( opts, 'name' ) || archive_name )
  archive_path = find_option( opts, 'archive_path' ) || File.join( Dir.pwd, name )
  dest_dir = find_option( opts, 'dest_dir' ) || deploy_dir
  FileUtils.cp( archive_path, dest_dir )
  archive = File.basename( archive_path )
  FileUtils.touch( dodeploy_file( archive, dest_dir ) )
  [archive, dest_dir]
end
deploy_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 91
def deploy_dir
  File.join( "#{server_dir}", "deployments" )
end
deploy_yaml(deployment_descriptor, opts = {}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 313
def deploy_yaml(deployment_descriptor, opts = {})
  name = normalize_yaml_name( find_option( opts, 'name' ) || deployment_name(opts[:root] || opts['root']) )
  dest_dir = opts[:dest_dir] || opts['dest_dir'] || deploy_dir
  deployment = File.join( dest_dir, name )
  File.open( deployment, 'w' ) do |file|
    YAML.dump( deployment_descriptor, file )
  end
  FileUtils.touch( dodeploy_file( name, dest_dir ) )
  [name, dest_dir]
end
deployed_file(name, deploy_dir = DeployUtils.deploy_dir) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 338
def deployed_file(name, deploy_dir = DeployUtils.deploy_dir)
  File.join( deploy_dir, "#{name}" ) + ".deployed"
end
deployers_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 95
def deployers_dir
  raise "Deployers directory no longer relevant"
end
deployment_descriptors() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 470
def deployment_descriptors
  Dir.glob( "#{deploy_dir}/*-knob.yml" ).collect { |d| File.basename( d ) }
end
deployment_name(root = Dir.pwd) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 111
def deployment_name(root = Dir.pwd)
  normalize_yaml_name( File.basename( root || Dir.pwd ) )
end
deployment_status() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 474
def deployment_status
  applications = {}
  deployment_descriptors.each do | descriptor |
    descriptor_path = File.join( deploy_dir, descriptor )
    appname = descriptor.sub( /\-knob.yml/, '' )
    applications[appname] = {}
    applications[appname][:descriptor] = descriptor_path
    applications[appname][:status] = case
                                     when File.exists?("#{descriptor_path}.dodeploy")
                                       "awaiting deployment"
                                     when File.exists?("#{descriptor_path}.deployed")
                                       "deployed"
                                     when File.exists?("#{descriptor_path}.failed")
                                       "deployment failed"
                                     else "unknown: try running `torquebox deploy #{appname}`"
                                     end
  end
  applications
end
dodeploy_file(name, deploy_dir = DeployUtils.deploy_dir) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 334
def dodeploy_file(name, deploy_dir = DeployUtils.deploy_dir)
  File.join( deploy_dir, "#{name}" ) + ".dodeploy"
end
eap?() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 82
def eap?
  index_html = File.join( jboss_home, 'welcome-content', 'index.html' )
  File.exists?( index_html ) && File.read( index_html ) =~ /EAP 6/
end
exec_command(cmd) click to toggle source

Used when we want to effectively replace this process with the given command. On Windows this does call Kernel#exec but on everything else we just delegate to fake_exec.

This is mainly so CTRL+C, STDIN, STDOUT, and STDERR work as expected across all operating systems.

# File lib/torquebox/deploy_utils.rb, line 396
def exec_command(cmd)
  exec(cmd)
  # windows? ? exec(cmd) : fake_exec(cmd)
end
fake_exec(cmd) click to toggle source

Used to run a command as a subprocess

# File lib/torquebox/deploy_utils.rb, line 402
def fake_exec(cmd)
  exiting = false
  IO.popen4(cmd) do |pid, stdin, stdout, stderr|
    stdout.sync = true
    stderr.sync = true
    trap("INT") do
      exiting = true
      stdin.close
      puts "caught SIGINT, shutting down"
      `taskkill /F /T /PID #{pid}` if windows?
    end

    # Don't join on stdin since interrupting a blocking read on
    # JRuby is pretty tricky
    Thread.new(stdin) { |stdin_io|
      begin
        until exiting
          stdin_io.write(readpartial(STDIN))
          stdin_io.flush
        end
      rescue Errno::EBADF, IOError
      end
    }

    # Join on stdout/stderr since they'll be closed
    # automatically once TorqueBox exits
    [ Thread.new(stdout) { |stdout_io|
        begin
          while true
            STDOUT.write(readpartial(stdout_io))
          end
        rescue EOFError
        end
      },

      Thread.new(stderr) { |stderr_io|
        begin
          while true
            STDERR.write(readpartial(stderr_io))
          end
        rescue EOFError
        end
      }
    ].each( &:join)
  end

end
find_option(opt, key) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 458
def find_option(opt, key)
  opt[key.to_sym] || opt[key] || ENV[key] || ENV[key.upcase]
end
freeze_gems(app_dir = Dir.pwd) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 284
def freeze_gems(app_dir = Dir.pwd)
  Dir.chdir( app_dir ) do
    jruby_command( '-S bundle package --all' )
    jruby_command( '-S bundle install --local --deployment' )
  end
end
is_deployed?( appname = deployment_name ) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 151
def is_deployed?( appname = deployment_name )
  File.exists?( File.join(deploy_dir, appname) )
end
jboss_conf() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 48
def jboss_conf
  ENV['TORQUEBOX_CONF'] || ENV['JBOSS_CONF'] || 'standalone'
end
jboss_home() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 31
def jboss_home
  jboss_home = File.expand_path(ENV['JBOSS_HOME']) if ENV['JBOSS_HOME']
  jboss_home ||= File.join(File.expand_path(ENV['TORQUEBOX_HOME']), "jboss") if ENV['TORQUEBOX_HOME']
  raise "$JBOSS_HOME is not set" unless jboss_home
  return jboss_home
end
jruby_command(cmd) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 375
def jruby_command(cmd)
  jruby = File.join( RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] )
  run_command( "#{jruby} #{cmd}" )
end
jruby_opts_properties() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 494
def jruby_opts_properties
  jruby_opts = ENV['JRUBY_OPTS']
  return "" if jruby_opts.nil?
  # Only convert -Xa.b, -Xa.b.c, -Xa.b.c.d style options to properties
  properties = jruby_opts.scan(/-X(\w+\..+?)(\s|$)/)
  properties.map { |matches| "-Djruby.#{matches.first}" }.join(' ')
end
modules_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 99
def modules_dir
  File.join( jboss_home, 'modules' )
end
normalize_archive_name(name) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 466
def normalize_archive_name(name)
  name[-5..-1] == '.knob' ? name : name + '.knob'
end
normalize_yaml_name(name) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 462
def normalize_yaml_name(name)
  name[-9..-1] == '-knob.yml' ? name : name + '-knob.yml'
end
opt_dir() click to toggle source

Used by upstart and launchd

# File lib/torquebox/deploy_utils.rb, line 58
def opt_dir
  File.join( sys_root, 'opt' )
end
opt_torquebox() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 62
def opt_torquebox
  File.join( opt_dir, 'torquebox' )
end
package_gems(app_dir, package_without) { || ... } click to toggle source
# File lib/torquebox/deploy_utils.rb, line 229
def package_gems(app_dir, package_without)
  # note - this is used instead of freeze gems because it
  # should cause the archive to capture .bundle/config,
  # thereby forcing the app to use the bundled gems. we delete
  # the deployment configuration for rubygems afterward
  bundler_config = File.join( app_dir, '.bundle/config' )
  if File.exists?( bundler_config )
    old_config = File.read( bundler_config )
  else
    old_config = nil
  end
  cmd = %w{-S bundle --local --deployment}
  unless package_without.empty?
    cmd << '--without'
    cmd << package_without
  end
  Dir.chdir( app_dir ) do
    jruby_command( '-S bundle package --all' )
    jruby_command( cmd.flatten.join(' ') )
  end
  yield if block_given?
ensure
  if File.exists?( bundler_config )
    if old_config
      File.open( bundler_config, 'w' ) { |io| io.write( old_config ) }
    else
      File.delete( bundler_config ) # there wasn't originally a config file there
    end
  end
end
precompile_assets(app_dir) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 223
def precompile_assets(app_dir)
  Dir.chdir( app_dir ) do
    jruby_command( "-S rake assets:precompile" )
  end
end
properties_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 87
def properties_dir
  config_dir
end
readpartial(stream) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 450
def readpartial(stream)
  windows? ? stream.read(1) : stream.readpartial(1024)
end
rubylib_with_bundler(load_path) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 518
def rubylib_with_bundler(load_path)
  bundler_load_paths = load_path.select { |p| p.include?('bundler') }
  rubylib = (ENV['RUBYLIB'] || '').dup # ENV strings are frozen
  unless rubylib.empty? || bundler_load_paths.empty?
    rubylib << ':'
  end
  rubylib << bundler_load_paths.join(':')
end
run_command(cmd) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 380
def run_command(cmd)
  old_rubyopt = ENV['RUBYOPT']
  begin
    ENV['RUBYOPT'] = ''
    puts `#{cmd} 2>&1`
  ensure
    ENV['RUBYOPT'] = old_rubyopt
  end
end
run_command_line(opts={}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 130
def run_command_line(opts={})
  options = ENV['JBOSS_OPTS'] || ''
  config_file = opts[:clustered] ? cluster_config_file : standalone_config_file
  options = "#{options} --server-config=#{config_file}"
  options = "#{options} -Dorg.torquebox.web.http.maxThreads=#{opts[:max_threads]}" if opts[:max_threads]
  options = "#{options} -b #{opts[:bind_address]}" if opts[:bind_address]
  options = "#{options} -Djboss.socket.binding.port-offset=#{opts[:port_offset]}" if opts[:port_offset]
  options = "#{options} -Dhttp.port=#{opts[:port]}" if opts[:port]
  options = "#{options} -Djboss.node.name=#{opts[:node_name]}" if opts[:node_name]
  options = "#{options} -Djboss.server.data.dir=#{opts[:data_directory]}" if opts[:data_directory]
  options = "#{options} -Dfile.encoding=UTF-8" if java.lang.System.getProperty('file.encoding') == 'MacRoman'
  options = "#{options} #{opts[:pass_through]}" if opts[:pass_through]
  if windows?
    cmd = "#{jboss_home.gsub('/', '\\')}\\bin\\standalone.bat"
  else
    cmd = "#{jboss_home}/bin/standalone.sh"
  end
  puts "#{cmd} #{options}" # Make it clear to the user what is being passed through to JBoss AS
  [cmd, options]
end
run_server(options={}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 155
def run_server(options={})
  puts "[WARNING] #{deployment_name} has not been deployed. Starting TorqueBox anyway." unless ( is_deployed? )

  Dir.chdir(jboss_home) do
    # don't send the gemfile from the current app, instead let
    # bundler suss it out itself for each deployed
    # app. Otherwise, they'll end up sharing this Gemfile, which
    # is probably not what we want.
    ENV.delete('BUNDLE_GEMFILE')
    # If called from rake within a rails app, bundler will try
    # to init itself via RUBYOPT, which we don't want
    ENV.delete('RUBYOPT')
    # Ensure bundler gets on the Ruby load path of the booted
    # TorqueBox instance if it's on the load path of this Ruby
    # runtime so we can find bundler and our own gems if used
    # with bundle install --deployment
    ENV['RUBYLIB'] = rubylib_with_bundler($:)

    options[:jvm_options] ||= ''
    options[:jvm_options] << " #{jruby_opts_properties}"
    options[:jvm_options] << " #{strip_jvm_properties_from_jruby_opts}"

    set_java_opts(options[:jvm_options].strip)
    print_server_config(options[:clustered])
    exec_command(run_command_line(options).join(' '))
  end
end
server_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 66
def server_dir
  File.join("#{jboss_home}","#{jboss_conf}" )
end
set_java_opts(options) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 125
def set_java_opts(options)
  ENV['JAVA_OPTS'] ||= "-Xms64m -Xmx768m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true"
  ENV['JAVA_OPTS'] = "#{ENV['JAVA_OPTS']} #{options}"
end
standalone_config_file() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 74
def standalone_config_file
  eap? ? "torquebox-full.xml" : "standalone.xml"
end
strip_jvm_properties_from_jruby_opts() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 502
def strip_jvm_properties_from_jruby_opts
  jruby_opts = ENV['JRUBY_OPTS']
  return '' if jruby_opts.nil?
  jvm_properties = []
  properties = jruby_opts.split(' ')
  properties.each do |property|
    if property =~ /^-J.+/
      jvm_properties << property.sub(/-J/, '')
      ENV['JRUBY_OPTS'] = ENV['JRUBY_OPTS'].sub(property, '')
    end
  end
  # get rid of any leftover spaces
  ENV['JRUBY_OPTS'] = ENV['JRUBY_OPTS'].split(' ').join(' ')
  jvm_properties.join(' ')
end
sys_root() click to toggle source

TODO: This is not windows friendly, is it?

# File lib/torquebox/deploy_utils.rb, line 53
def sys_root
  '/'
end
torquebox_home() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 38
def torquebox_home
  torquebox_home = nil
  if ( ENV['TORQUEBOX_HOME'] )
    torquebox_home = File.expand_path(ENV['TORQUEBOX_HOME'])
  else
    torquebox_home = TorqueBox::Server.torquebox_home
  end
  torquebox_home
end
torquebox_modules_dir() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 103
def torquebox_modules_dir
  File.join( modules_dir, 'system', 'layers', 'torquebox', 'org', 'torquebox' )
end
undeploy_archive(opts = {}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 342
def undeploy_archive(opts = {})
  undeploy( normalize_archive_name( find_option( opts, 'name' ) || archive_name( opts[:root] ) ), opts )
end
undeploy_yaml(opts = {}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 346
def undeploy_yaml(opts = {})
  undeploy( normalize_yaml_name( find_option( opts, 'name' ) || deployment_name( opts[:root] ) ), opts )
end
windows?() click to toggle source
# File lib/torquebox/deploy_utils.rb, line 454
def windows?
  RbConfig::CONFIG['host_os'] =~ /mswin/
end

Private Class Methods

print_server_config(clustered) click to toggle source
undeploy(name, opts = {}) click to toggle source
# File lib/torquebox/deploy_utils.rb, line 529
def undeploy(name, opts = {})
  puts "Attempting to undeploy #{name}"
  from_dir = find_option( opts, 'deploy_dir' ) || deploy_dir
  deployment = File.join( from_dir, name )
  undeployed = false
  if File.exists?( dodeploy_file( name ) )
    FileUtils.rm_rf( dodeploy_file( name ) )
    undeployed = true
  end
  if File.exists?( deployed_file( name ) )
    FileUtils.rm_rf( deployed_file( name ) )
    undeployed = true
  end
  if File.exists?( deployment )
    FileUtils.rm_rf( deployment )
    undeployed = true
  end

  if undeployed
    [name, from_dir]
  else
    puts "Can't undeploy #{deployment}. It does not appear to be deployed."
  end
end