You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by Michal Fojtik <mf...@redhat.com> on 2010/12/01 14:31:05 UTC

Re: [PATCH] Allow for dynamic driver selection via header, storing it in Thread.current.

On 30/11/10 17:12 -0500, tcrawley@redhat.com wrote:

Hi,

</snip>
!! Unexpected error while processing request: undefined method `match' for
nil:NilClass
undefined method `match' for nil:NilClass
   ././lib/sinatra/rack_driver_select.rb:18:in `extract_driver'
     ././lib/sinatra/rack_driver_select.rb:10:in `call'
</snip>

There should be an easy fix, just check if header is set or not.
Otherwise, this patch looks good to me, ACK after this issue will be fixed.

   -- Michal


>From: Tobias Crawley <tc...@redhat.com>
>
>---
> server/lib/drivers.rb                      |   97 +++++++++++++++-------------
> server/lib/sinatra/lazy_auth.rb            |    2 +-
> server/lib/sinatra/rabbit.rb               |    8 +-
> server/lib/sinatra/rack_driver_select.rb   |   22 ++++++
> server/server.rb                           |   41 ++++++++----
> server/views/api/drivers.xml.haml          |    6 ++
> server/views/api/show.html.haml            |    4 +-
> server/views/api/show.xml.haml             |    2 +-
> server/views/errors/backend_error.xml.haml |    2 +-
> server/views/layout.html.haml              |    2 +-
> 10 files changed, 117 insertions(+), 69 deletions(-)
> create mode 100644 server/lib/sinatra/rack_driver_select.rb
> create mode 100644 server/views/api/drivers.xml.haml
>
>diff --git a/server/lib/drivers.rb b/server/lib/drivers.rb
>index 6e31bb7..43c5bea 100644
>--- a/server/lib/drivers.rb
>+++ b/server/lib/drivers.rb
>@@ -1,51 +1,60 @@
>-DRIVERS = {
>-  :ec2 => { :name => "EC2" },
>-  :rackspace => { :name => "Rackspace" },
>-  :gogrid => { :name => "Gogrid" },
>-  :rhevm => { :name => "RHEVM" },
>-  :rimuhosting => { :name => "RimuHosting"},
>-  :opennebula => { :name => "Opennebula", :class => "OpennebulaDriver" },
>-  :terremark => { :name => "Terremark"},
>-  :azure => { :name => "Azure" },
>-  :mock => { :name => "Mock" }
>-}
>-
>-DEFAULT_COLLECTIONS = [
>-  :hardware_profiles,
>-  :images,
>-  :instances,
>-  :instance_states,
>-  :realms,
>-  :storage_volumes,
>-  :storage_snapshots
>-]
>-
>-DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
>-
>-def driver_name
>-  DRIVERS[DRIVER][:name]
>-end
>-
>-def driver_class_name
>-  basename = DRIVERS[DRIVER][:class] || "#{driver_name}Driver"
>-  "Deltacloud::Drivers::#{driver_name}::#{basename}"
>-end
>+module Deltacloud
>+  DRIVERS = {
>+    :ec2 => { :name => "EC2" },
>+    :rackspace => { :name => "Rackspace" },
>+    :gogrid => { :name => "Gogrid" },
>+    :rhevm => { :name => "RHEVM" },
>+    :rimuhosting => { :name => "RimuHosting"},
>+    :opennebula => { :name => "Opennebula", :class => "OpennebulaDriver" },
>+    :terremark => { :name => "Terremark"},
>+    :azure => { :name => "Azure" },
>+    :mock => { :name => "Mock" }
>+  }
>+
>+  DEFAULT_COLLECTIONS = [
>+    :hardware_profiles,
>+    :images,
>+    :instances,
>+    :instance_states,
>+    :realms,
>+    :storage_volumes,
>+    :storage_snapshots
>+  ]
>+
>+  DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
>+
>+  def driver_symbol
>+    (Thread.current[:driver] || DRIVER).to_sym
>+  end
>
>-def driver_source_name
>-  File.join("deltacloud", "drivers", "#{DRIVER}", "#{DRIVER}_driver.rb")
>-end
>+  def driver_name
>+    DRIVERS[:"#{driver_symbol}"][:name]
>+  end
>
>-def driver_mock_source_name
>-  return File.join('deltacloud', 'drivers', DRIVER.to_s, "#{DRIVER}_driver.rb") if driver_name.eql? 'Mock'
>-end
>+  def driver_class_name
>+    basename = DRIVERS[:"#{driver_symbol}"][:class] || "#{driver_name}Driver"
>+    "Deltacloud::Drivers::#{driver_name}::#{basename}"
>+  end
>
>-def driver
>-  require driver_source_name
>-  #require 'deltacloud/base_driver/mock_driver.rb'
>+  def driver_source_name
>+    File.join("deltacloud", "drivers", "#{driver_symbol}", "#{driver_symbol}_driver.rb")
>+  end
>
>-  if Sinatra::Application.environment.eql? :test
>-    require driver_mock_source_name if driver_mock_source_name
>+  def driver_mock_source_name
>+    return File.join('deltacloud', 'drivers', "#{driver_symbol}",
>+                     "#{driver_symbol}_driver.rb") if driver_name.eql? 'Mock'
>   end
>
>-  @driver ||= eval( driver_class_name ).new
>+  def driver
>+    require driver_source_name
>+    #require 'deltacloud/base_driver/mock_driver.rb'
>+
>+    if Sinatra::Application.environment.eql? :test
>+      require driver_mock_source_name if driver_mock_source_name
>+    end
>+
>+    @driver ||= eval( driver_class_name ).new
>+  end
> end
>+
>+include Deltacloud
>diff --git a/server/lib/sinatra/lazy_auth.rb b/server/lib/sinatra/lazy_auth.rb
>index 2a26fdf..99c416a 100644
>--- a/server/lib/sinatra/lazy_auth.rb
>+++ b/server/lib/sinatra/lazy_auth.rb
>@@ -40,7 +40,7 @@ module Sinatra
>     end
>
>     def authorize!
>-      r = "#{DRIVER}-deltacloud@#{HOSTNAME}"
>+      r = "#{driver_symbol}-deltacloud@#{HOSTNAME}"
>       response['WWW-Authenticate'] = %(Basic realm="#{r}")
>       throw(:halt, [401, "Not authorized\n"])
>     end
>diff --git a/server/lib/sinatra/rabbit.rb b/server/lib/sinatra/rabbit.rb
>index 94c74e3..05bd6c5 100644
>--- a/server/lib/sinatra/rabbit.rb
>+++ b/server/lib/sinatra/rabbit.rb
>@@ -60,7 +60,7 @@ module Sinatra
>       def control(&block)
>         op = self
>         @control = Proc.new do
>-          op.check_capability(driver)
>+          op.check_capability(Deltacloud::driver)
>           op.validate(params)
>           instance_eval(&block)
>         end
>@@ -133,7 +133,7 @@ module Sinatra
>       end
>
>       def generate_documentation
>-        coll, oper, features = self, @operations, driver.features(name)
>+        coll, oper, features = self, @operations, Deltacloud::driver.features(name)
>         ::Sinatra::Application.get("/api/docs/#{@name}") do
>           @collection, @operations, @features = coll, oper, features
>           respond_to do |format|
>@@ -206,9 +206,9 @@ module Sinatra
>     # operation on this collection.
>     def collection(name, &block)
>       raise DuplicateCollectionException if collections[name]
>-      return unless driver.has_collection?(name.to_sym)
>+      return unless Deltacloud::driver.has_collection?(name.to_sym)
>       collections[name] = Collection.new(name, &block)
>-      collections[name].add_feature_params(driver.features(name))
>+      collections[name].add_feature_params(Deltacloud::driver.features(name))
>       collections[name].generate
>     end
>
>diff --git a/server/lib/sinatra/rack_driver_select.rb b/server/lib/sinatra/rack_driver_select.rb
>new file mode 100644
>index 0000000..24c36de
>--- /dev/null
>+++ b/server/lib/sinatra/rack_driver_select.rb
>@@ -0,0 +1,22 @@
>+class RackDriverSelect
>+
>+  def initialize(app, opts={})
>+    @app = app
>+    @opts = opts
>+  end
>+
>+  def call(env)
>+    original_driver = Thread.current[:driver]
>+    new_driver = extract_driver(env)
>+    Thread.current[:driver] = new_driver if new_driver
>+    @app.call(env)
>+  ensure
>+    Thread.current[:driver] = original_driver
>+  end
>+
>+  def extract_driver(env)
>+    driver_name = env['HTTP_HEADERS'].match(/X\-Deltacloud\-Driver:(\w+)/i).to_a
>+    return driver_name[1] if driver_name[1]
>+  end
>+
>+end
>diff --git a/server/server.rb b/server/server.rb
>index d3f7d8a..076859d 100644
>--- a/server/server.rb
>+++ b/server/server.rb
>@@ -10,6 +10,12 @@ require 'erb'
> require 'haml'
> require 'open3'
> require 'lib/deltacloud/helpers/blob_stream'
>+require 'sinatra/rack_driver_select'
>+
>+set :version, '0.1.0'
>+
>+
>+use RackDriverSelect
>
> configure do
>   set :raise_errors => false
>@@ -48,23 +54,28 @@ Sinatra::Application.register Sinatra::RespondTo
> # Redirect to /api
> get '/' do redirect url_for('/api'); end
>
>+get '/api/drivers\/?' do
>+  respond_to do |format|
>+    format.xml { haml :"api/drivers" }
>+  end
>+end
>+
> get '/api\/?' do
>-    @version = 0.1
>-    if params[:force_auth]
>-      return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
>-    end
>-    respond_to do |format|
>-        format.xml { haml :"api/show" }
>-        format.json do
>-          { :api => {
>-            :version => @version,
>-            :driver => DRIVER,
>-            :links => entry_points.collect { |l| { :rel => l[0], :href => l[1]} }
>-            }
>-          }.to_json
>-        end
>-        format.html { haml :"api/show" }
>+  if params[:force_auth]
>+    return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
>+  end
>+  respond_to do |format|
>+    format.xml { haml :"api/show" }
>+    format.json do
>+      { :api => {
>+          :version => settings.version,
>+          :driver => driver_symbol,
>+          :links => entry_points.collect { |l| { :rel => l[0], :href => l[1]} }
>+        }
>+      }.to_json
>     end
>+    format.html { haml :"api/show" }
>+  end
> end
>
> # Rabbit DSL
>diff --git a/server/views/api/drivers.xml.haml b/server/views/api/drivers.xml.haml
>new file mode 100644
>index 0000000..7beb9c8
>--- /dev/null
>+++ b/server/views/api/drivers.xml.haml
>@@ -0,0 +1,6 @@
>+%api{ :version => settings.version }
>+  %drivers
>+    - DRIVERS.each do |id, details|
>+      %driver{ :id => id }
>+        %name<
>+          =details[:name]
>diff --git a/server/views/api/show.html.haml b/server/views/api/show.html.haml
>index 0077972..74ec175 100644
>--- a/server/views/api/show.html.haml
>+++ b/server/views/api/show.html.haml
>@@ -1,5 +1,5 @@
> %h1
>-  API v#{@version}
>+  API v#{settings.version}
>
> %ul
>   - collections.keys.sort_by { |k| k.to_s }.each do |key|
>@@ -12,4 +12,4 @@
>             = op
>   %li
>     %strong
>-      %a{:href => url_for("/api/docs")} Documentation (v#{@version})
>+      %a{:href => url_for("/api/docs")} Documentation (#{settings.version})
>diff --git a/server/views/api/show.xml.haml b/server/views/api/show.xml.haml
>index 70c26c9..f68fd79 100644
>--- a/server/views/api/show.xml.haml
>+++ b/server/views/api/show.xml.haml
>@@ -1,4 +1,4 @@
>-%api{ :version=>@version, :driver=>DRIVER }
>+%api{ :version => settings.version, :driver => driver_symbol }
>   - for entry_point in entry_points
>     %link{ :rel=>entry_point[0], :href=>entry_point[1] }
>       - for feature in driver.features(entry_point[0])
>diff --git a/server/views/errors/backend_error.xml.haml b/server/views/errors/backend_error.xml.haml
>index 75866eb..4aba8c0 100644
>--- a/server/views/errors/backend_error.xml.haml
>+++ b/server/views/errors/backend_error.xml.haml
>@@ -1,6 +1,6 @@
> %error{:url => "#{request.env['REQUEST_URI']}", :status => "#{response.status}"}
>   %kind backend_error
>-  %backend{ :driver => DRIVER }
>+  %backend{ :driver => driver_symbol }
>     %code= @error.code
>     %cause= @error.cause
>     - if @error.details
>diff --git a/server/views/layout.html.haml b/server/views/layout.html.haml
>index c46b15b..1556272 100644
>--- a/server/views/layout.html.haml
>+++ b/server/views/layout.html.haml
>@@ -19,7 +19,7 @@
>         = yield
>       #footer
>         #driver_info
>-          Driver: #{DRIVER}
>+          Driver: #{driver_symbol} | API version: #{settings.version}
>         #copyright
>           Copyright 2009, 2010
>           %a{:href => 'http://redhat.com'} Red Hat
>--
>1.7.3.2
>

-- 
--------------------------------------------------------
Michal Fojtik, mfojtik@redhat.com
Deltacloud API: http://deltacloud.org
--------------------------------------------------------