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
--------------------------------------------------------