incubator-deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@redhat.com
Subject [PATCH core] Added support to daemonize Deltacloud and log to the syslog
Date Thu, 11 Aug 2011 13:03:54 GMT
From: Michal Fojtik <mfojtik@redhat.com>


Signed-off-by: Michal fojtik <mfojtik@redhat.com>
---
 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


Mime
View raw message