module TorqueBox::DeployUtils
Public Class Methods
# File lib/torquebox/deploy_utils.rb, line 107 def archive_name(root = Dir.pwd) normalize_archive_name( File.basename( root || Dir.pwd ) ) end
# 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
# 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
# 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
# File lib/torquebox/deploy_utils.rb, line 78 def cluster_config_file eap? ? "torquebox-full-ha.xml" : "standalone-ha.xml" end
# File lib/torquebox/deploy_utils.rb, line 70 def config_dir File.join("#{server_dir}","configuration") end
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
# 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
TODO: This is not windows friendly
# File lib/torquebox/deploy_utils.rb, line 351 def create_symlink unless File.exist? opt_dir success = true if !File.writable?( sys_root ) puts "Cannot write to #{sys_root}. Please ensure #{opt_torquebox} points to your torquebox installation." success = false else puts "Creating #{opt_dir}" Dir.new( opt_dir ) end end unless File.exist?( opt_torquebox ) if File.writable?( opt_dir ) puts "Linking #{opt_torquebox} to #{torquebox_home}" File.symlink( torquebox_home, opt_torquebox ) else puts "Cannot link #{opt_torquebox} to #{torquebox_home}" success = false end end success end
# 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
# File lib/torquebox/deploy_utils.rb, line 91 def deploy_dir File.join( "#{server_dir}", "deployments" ) end
# 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
# File lib/torquebox/deploy_utils.rb, line 338 def deployed_file(name, deploy_dir = DeployUtils.deploy_dir) File.join( deploy_dir, "#{name}" ) + ".deployed" end
# File lib/torquebox/deploy_utils.rb, line 95 def deployers_dir raise "Deployers directory no longer relevant" end
# File lib/torquebox/deploy_utils.rb, line 470 def deployment_descriptors Dir.glob( "#{deploy_dir}/*-knob.yml" ).collect { |d| File.basename( d ) } end
# File lib/torquebox/deploy_utils.rb, line 111 def deployment_name(root = Dir.pwd) normalize_yaml_name( File.basename( root || Dir.pwd ) ) end
# 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
# File lib/torquebox/deploy_utils.rb, line 334 def dodeploy_file(name, deploy_dir = DeployUtils.deploy_dir) File.join( deploy_dir, "#{name}" ) + ".dodeploy" end
# 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
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
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
# 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
# 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
# File lib/torquebox/deploy_utils.rb, line 151 def is_deployed?( appname = deployment_name ) File.exists?( File.join(deploy_dir, appname) ) end
# File lib/torquebox/deploy_utils.rb, line 48 def jboss_conf ENV['TORQUEBOX_CONF'] || ENV['JBOSS_CONF'] || 'standalone' end
# 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
# 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
# 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
# File lib/torquebox/deploy_utils.rb, line 99 def modules_dir File.join( jboss_home, 'modules' ) end
# File lib/torquebox/deploy_utils.rb, line 466 def normalize_archive_name(name) name[-5..-1] == '.knob' ? name : name + '.knob' end
# File lib/torquebox/deploy_utils.rb, line 462 def normalize_yaml_name(name) name[-9..-1] == '-knob.yml' ? name : name + '-knob.yml' end
Used by upstart and launchd
# File lib/torquebox/deploy_utils.rb, line 58 def opt_dir File.join( sys_root, 'opt' ) end
# File lib/torquebox/deploy_utils.rb, line 62 def opt_torquebox File.join( opt_dir, 'torquebox' ) end
# 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
# 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
# File lib/torquebox/deploy_utils.rb, line 87 def properties_dir config_dir end
# File lib/torquebox/deploy_utils.rb, line 450 def readpartial(stream) windows? ? stream.read(1) : stream.readpartial(1024) end
# 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
# 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
# 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
# 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
# File lib/torquebox/deploy_utils.rb, line 66 def server_dir File.join("#{jboss_home}","#{jboss_conf}" ) end
# 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
# File lib/torquebox/deploy_utils.rb, line 74 def standalone_config_file eap? ? "torquebox-full.xml" : "standalone.xml" end
# 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
TODO: This is not windows friendly, is it?
# File lib/torquebox/deploy_utils.rb, line 53 def sys_root '/' end
# 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
# File lib/torquebox/deploy_utils.rb, line 103 def torquebox_modules_dir File.join( modules_dir, 'system', 'layers', 'torquebox', 'org', 'torquebox' ) end
# 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
# 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
# File lib/torquebox/deploy_utils.rb, line 454 def windows? RbConfig::CONFIG['host_os'] =~ /mswin/ end
Private Class Methods
# File lib/torquebox/deploy_utils.rb, line 554 def print_server_config(clustered) config_file = clustered ? cluster_config_file : standalone_config_file config_path = File.join(config_dir, config_file) puts "Booting AS7 from configuration #{config_path}" end
# 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