From: Michal Fojtik <[email protected]>
Signed-off-by: Michal fojtik <[email protected]> --- server/NOTICE | 3 + server/bin/deltacloudd | 38 ++++++--- server/lib/deltacloud/base_driver/exceptions.rb | 15 ++-- server/lib/deltacloud/drivers/mock/mock_driver.rb | 2 +- server/lib/sinatra/body_proxy.rb | 34 ++++++++ server/lib/sinatra/rack_syslog.rb | 91 +++++++++++++++++++++ server/server.rb | 11 ++- 7 files changed, 169 insertions(+), 25 deletions(-) create mode 100644 server/lib/sinatra/body_proxy.rb create mode 100644 server/lib/sinatra/rack_syslog.rb diff --git a/server/NOTICE b/server/NOTICE index 00f4354..a1415cf 100644 --- a/server/NOTICE +++ b/server/NOTICE @@ -17,3 +17,6 @@ This product includes software developed by the jQuery Project This product includes icons created by David Vignon licensed under LGPL (http://www.icon-king.com/) + +This product includes software developed by Christian Neukirchen +(https://github.com/rack/rack) diff --git a/server/bin/deltacloudd b/server/bin/deltacloudd index dba99ab..2c80dd4 100755 --- a/server/bin/deltacloudd +++ b/server/bin/deltacloudd @@ -45,6 +45,11 @@ BANNER 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 } @@ -119,20 +124,23 @@ end ENV["API_HOST"] = "localhost" unless ENV["API_HOST"] ENV["API_PORT"] = "3001" unless ENV["API_PORT"] -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" +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 -puts msg + 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 -puts - dirname="#{File.dirname(__FILE__)}/.." @@ -180,6 +188,12 @@ else 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" @@ -191,10 +205,6 @@ else rerun.join else thin = Thin::Runner.new(argv_opts) - begin - thin.run! - rescue Exception => e - puts "ERROR: #{e.message}" - end + thin.run! end end diff --git a/server/lib/deltacloud/base_driver/exceptions.rb b/server/lib/deltacloud/base_driver/exceptions.rb index d95191c..81d4543 100644 --- a/server/lib/deltacloud/base_driver/exceptions.rb +++ b/server/lib/deltacloud/base_driver/exceptions.rb @@ -116,15 +116,16 @@ module Deltacloud def safely(&block) begin block.call - rescue => e + rescue + report_method = $stderr.respond_to?(:err) ? :err : :puts Deltacloud::ExceptionHandler::exceptions.each do |exdef| - raise exdef.handler(e) if exdef.match?(e) + if exdef.match?($!) + $stderr.send(report_method, "#{[$!.class.to_s, $!.message].join(':')}\n#{$!.backtrace.join("\n")}") + raise exdef.handler($!) + end end - $stderr.puts "# UNCAUGHT EXCEPTION ~> '#{e.class}' - " - $stderr.puts "# #{e.message}" - $stderr.puts "# #{e.backtrace.join("\n")}" - $stderr.puts "##############" - raise BackendError.new(e, e.message) + $stderr.send(report_method, "[NO HANDLED] #{[$!.class.to_s, $!.message].join(': ')}\n#{$!.backtrace.join("\n")}") + raise BackendError.new($!, $!.message) end end diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb index 77d7738..abb48a5 100644 --- a/server/lib/deltacloud/drivers/mock/mock_driver.rb +++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb @@ -137,8 +137,8 @@ class MockDriver < Deltacloud::BaseDriver def create_image(credentials, opts={}) check_credentials(credentials) instance = instance(credentials, :id => opts[:id]) - raise 'CreateImageNotSupported' unless instance.can_create_image? safely do + raise 'CreateImageNotSupported' unless instance and instance.can_create_image? image = { :id => opts[:name], :name => opts[:name], diff --git a/server/lib/sinatra/body_proxy.rb b/server/lib/sinatra/body_proxy.rb new file mode 100644 index 0000000..5a3308d --- /dev/null +++ b/server/lib/sinatra/body_proxy.rb @@ -0,0 +1,34 @@ +# This code was originaly copied from Rack::BodyProxy +# https://github.com/rack/rack/blob/master/lib/rack/body_proxy.rb +# +# Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen> + +module Rack + class BodyProxy + def initialize(body, &block) + @body, @block, @closed = body, block, false + end + + def respond_to?(*args) + super or @body.respond_to?(*args) + end + + def close + raise IOError, "closed stream" if @closed + begin + @body.close if @body.respond_to? :close + ensure + @block.call + @closed = true + end + end + + def closed? + @closed + end + + def method_missing(*args, &block) + @body.__send__(*args, &block) + end + end +end diff --git a/server/lib/sinatra/rack_syslog.rb b/server/lib/sinatra/rack_syslog.rb new file mode 100644 index 0000000..cabcf89 --- /dev/null +++ b/server/lib/sinatra/rack_syslog.rb @@ -0,0 +1,91 @@ +require 'syslog' +require 'lib/sinatra/body_proxy' + +class SyslogFile < File + + def initialize + @log = Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_LOCAL5) + end + + def write(string) + @log.warning(string) if string.strip.length > 0 + return string.chars.count + end + + def info(msg) + @log.info(msg) + end + + def err(msg) + @log.err(msg) + end + + alias :warning :err + +end + +if settings.environment == :production + $stdout = SyslogFile.new + $stderr = $stdout +end + +# Code bellow was originaly copied from Rack::CommonLogger +# https://raw.github.com/rack/rack/master/lib/rack/commonlogger.rb + +module Rack + # Rack::CommonLogger forwards every request to an +app+ given, and + # logs a line in the Apache common log format to the +logger+, or + # rack.errors by default. + class SyslogLogger + + # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common + # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 - + # %{%s - %s [%s] "%s %s%s %s" %d %s\n} % + FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} + + def initialize(app, logger=nil) + @app = app + @logger = logger || $stdout + end + + def call(env) + began_at = Time.now + status, header, body = @app.call(env) + header = Utils::HeaderHash.new(header) + body = Rack::BodyProxy.new(body) { log(env, status, header, began_at) } + [status, header, body] + end + + private + + def log(env, status, header, began_at) + now = Time.now + length = extract_content_length(header) + + if status.to_s =~ /5(\d{2})/ + method = :err + else + method = :info + end + + logger = @logger || env['rack.errors'] + logger.send(method, FORMAT % [ + env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-", + env["REMOTE_USER"] || "-", + now.strftime("%d/%b/%Y %H:%M:%S"), + env["REQUEST_METHOD"], + env["PATH_INFO"], + env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"], + env["HTTP_VERSION"], + status.to_s[0..3], + length, + now - began_at ]) + end + + def extract_content_length(headers) + value = headers['Content-Length'] or return '-' + value.to_s == '0' ? '-' : value + end + end +end + diff --git a/server/server.rb b/server/server.rb index 60c1d36..85b7a6d 100644 --- a/server/server.rb +++ b/server/server.rb @@ -30,7 +30,7 @@ require 'sinatra/rack_runtime' require 'sinatra/rack_etag' require 'sinatra/rack_date' require 'sinatra/rack_matrix_params' - +require 'sinatra/rack_syslog' set :version, '0.3.0' include Deltacloud::Drivers @@ -46,14 +46,19 @@ use Rack::MediaType use Rack::Date configure do - set :raise_errors => false - set :show_exceptions, false set :views, File.dirname(__FILE__) + '/views' set :public, File.dirname(__FILE__) + '/public' # Try to load the driver on startup to fail early if there are issues driver end +configure :production do + use Rack::SyslogLogger + disable :logging + enable :show_errors + set :dump_errors, false +end + configure :development do # So we can just use puts for logging $stdout.sync = true -- 1.7.4.1
