#!/usr/bin/env ruby require 'rubygems' require 'optparse' require 'yaml' # See if we can require +name+ and return +true+ if the library is there, # +false+ otherwise. Note that, as a side effect, the library will be # loaded def library_present?(name) begin require name true rescue LoadError false end end DEFAULT_CONFIG = "~/.deltacloud/config" options = { :env => 'development' } optparse = OptionParser.new do |opts| opts.banner = < [options] Options: BANNER opts.on( '-i', '--driver DRIVER', 'Driver to use') do |driver| ENV["API_DRIVER"] = driver end opts.on( '-r', '--hostname HOSTNAME', 'Bind to HOST address (default: localhost)') do |host| ENV["API_HOST"] = host end opts.on( '-p', '--port PORT', 'Use PORT (default: 3001)') do |port| ENV["API_PORT"] = port end opts.on( '-P', '--provider PROVIDER', 'Use PROVIDER (default is set in the driver)') do |provider| ENV['API_PROVIDER'] = provider end opts.on( '-c', '--config [FILE]', 'Read provider and other config from FILE (default: ~/.deltacloud/config)') do |config| options[:config] = File::expand_path(config || DEFAULT_CONFIG) end opts.on( '-e', '--env ENV', 'Environment (default: "development")') { |env| options[:env] = env } opts.on( '-d', '--daemon', 'Run daemonized in the background, logging to SYSLOG (default: "disabled")') do options[:daemon] = true end opts.on( '-u', '--user USER', 'User to run daemon as. Use with -d (default: "nobody")') { |user| options[:user] = user } opts.on( '', '--pid PID', 'File to store PID (default: tmp/pids/thin.pid)') { |pid| options[:pid] = pid } opts.on( '-l', '--drivers', 'List available drivers') { |env| options[:drivers] = true } opts.on( '-s', '--ssl', 'Enable SSL (default: disabled)') { |ssl| options[:ssl] = true } opts.on( '-k', '--ssl-key KEY', 'SSL key file to use') { |key| options[:ssl_key] = key } opts.on( '-C', '--ssl-cert CERT', 'SSL certificate file to use') { |cert| options[:ssl_cert] = cert } opts.on( '-t', '--timeout TIMEOUT', 'Timeout for single request (default: 60)') do |timeout| ENV["API_TIMEOUT"] = timeout end opts.on( '-h', '--help', '') { options[:help] = true } opts.separator <)" puts "To list all available drivers try: deltacloudd --drivers" exit(1) end if options[:drivers] require 'server.rb' puts "Available drivers:\n\n" puts "* " + driver_config.keys.map{ |d| d.to_s }.join("\n* ") puts exit(0) end if options[:ssl] unless options[:ssl_key] puts "You need to set SSL key using '-k /path/to/keyfile.key'" exit(1) end unless options[:ssl_cert] puts "You need to set SSL certificate using '-C /path/to/certificate.crt'" exit(1) end end if options[:config] cfg = YAML::load(File.read(options[:config])) if c = cfg[ENV["API_DRIVER"].to_sym] ENV["API_PROVIDER"] ||= c[:provider] ENV["API_USER"] ||= c[:user] ENV["API_PASSWORD"] ||= c[:password] end end ENV["API_HOST"] = "localhost" unless ENV["API_HOST"] ENV["API_PORT"] = "3001" unless ENV["API_PORT"] unless options[:daemon] msg = "Starting Deltacloud API :: #{ENV["API_DRIVER"]} " msg << ":: #{ENV['API_PROVIDER']} " if ENV['API_PROVIDER'] if options[:ssl] msg << ":: https://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/api" else msg << ":: http://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/api" end puts msg puts end if ENV['API_USER'] && ENV['API_PASSWORD'] puts "Warning: API_USER and API_PASSWORD set in environment" puts " anybody can access this server with your credentials" puts end dirname="#{File.dirname(__FILE__)}/.." have_thin = library_present?('thin') have_rerun = library_present?('rerun') unless have_thin require 'rack' # We can't chdir with webrick so add our root directory # onto the load path $: << dirname # Read in config.ru and convert it to an instance of Rack::Builder cfgfile = File.read(File.join(dirname, 'config.ru')) inner_app = eval("Rack::Builder.new {(" + cfgfile + "\n )}.to_app", nil, 'config.ru') app = Rack::Builder.new { use Rack::CommonLogger # apache-like logging use Rack::Reloader if options[:env] == "development" set :root, dirname # Set Sinatra root since we can't chdir to ../ run inner_app }.to_app # There's a bug with string ports on JRuby so convert to int # http://jira.codehaus.org/browse/JRUBY-4868 port = ENV["API_PORT"].to_i puts "=> Ctrl-C to shutdown server" Rack::Handler::WEBrick.run(app, :Host => ENV["API_HOST"], :Port => port, :AccessLog => []) else argv_opts = ARGV.clone argv_opts << ['start'] unless Thin::Runner.commands.include?(options[0]) argv_opts << ['--address', ENV["API_HOST"] ] argv_opts << ['--port', ENV["API_PORT"] ] argv_opts << ['--rackup', 'config.ru' ] argv_opts << ['--chdir', dirname ] argv_opts << ['-e', options[:env] ] argv_opts << ['--timeout', ENV["API_TIMEOUT"] || '60'] argv_opts << ['--threaded', '-D' ] if options[:ssl] argv_opts << [ '--ssl', '--ssl-key-file', options[:ssl_key], '--ssl-cert-file', options[:ssl_cert]] end if options[:daemon] options[:env] = "production" argv_opts << [ "--daemonize", "--user", options[:user] || 'nobody', "--tag", "deltacloud-#{ENV['API_DRIVER']}"] argv << [ "--pid", options[:pid]] if options[:pid] end argv_opts.flatten! if have_rerun && options[:env] == "development" argv_opts.unshift "thin" command = argv_opts.join(" ") topdir = File::expand_path(File::join(File::dirname(__FILE__), "..")) rerun = Rerun::Runner.new(command, :dir => topdir) rerun.start rerun.join else thin = Thin::Runner.new(argv_opts) thin.run! end end