You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2012/05/21 12:06:41 UTC

Deltacloud revamp using Sinatra::Base (rev 3 - final? ;-)

Hi,

Sorry for the 'super-big-patch' once again, but this should be the final stable
version with all nits and tests fixed so far.

The test that does not work include RHEV-M (vcr fixtures need to refresh).
Revision 3 also include a basic test suite for the new library code to assure
the drivers API is stable and various feature-related fixes, including the
constraints settings.

The final code should run fine under Ruby 1.9 and also on Ruby 1.8.
I don't have any github repo right now, because maintaing those turns to be a
nightmare, since I need to rebase after every push.

  -- Michal


[PATCH core 05/51] Core: Added Deltacloud::API class and helpers to serve the default entrypoint

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/helpers.rb |    2 +-
 server/lib/deltacloud/server.rb  | 1280 +-------------------------------------
 2 files changed, 29 insertions(+), 1253 deletions(-)

diff --git a/server/lib/deltacloud/helpers.rb b/server/lib/deltacloud/helpers.rb
index dc382bd..8e265fc 100644
--- a/server/lib/deltacloud/helpers.rb
+++ b/server/lib/deltacloud/helpers.rb
@@ -1,4 +1,3 @@
-#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.  The
@@ -91,5 +90,6 @@ module Deltacloud::Collections
     def self.route_for(url)
       "#{settings.root_url}#{url}"
     end
+
   end
 end
diff --git a/server/lib/deltacloud/server.rb b/server/lib/deltacloud/server.rb
index bb40bcc..fced64b 100644
--- a/server/lib/deltacloud/server.rb
+++ b/server/lib/deltacloud/server.rb
@@ -13,1270 +13,46 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'sinatra'
-require 'deltacloud'
+require 'rubygems'
+require 'crack'
 require 'json'
-require 'sinatra/rack_accept'
-require 'sinatra/static_assets'
-require 'sinatra/rabbit'
-require 'sinatra/lazy_auth'
-require 'erb'
+require 'yaml'
 require 'haml'
-require 'open3'
-require 'sinatra/sinatra_verbose'
-require 'sinatra/rack_driver_select'
-require 'sinatra/rack_runtime'
-require 'sinatra/rack_etag'
-require 'sinatra/rack_date'
-require 'sinatra/rack_matrix_params'
-require 'sinatra/rack_syslog'
-
-set :version, '0.5.0'
-
-include Deltacloud::Drivers
-set :drivers, Proc.new { driver_config }
-
-Sinatra::Application.register Rack::RespondTo
-
-use Rack::ETag
-use Rack::Runtime
-use Rack::MatrixParams
-use Rack::DriverSelect
-use Rack::MediaType
-use Rack::Date
-use Rack::CommonLogger
-
-configure do
-  set :root_url, "/api"
-  set :views, File::join($top_srcdir, 'views')
-  # NOTE: Change :public to :public_folder once we update sinatra to 1.3
-  # set :public_folder, File::join($top_srcdir, 'public')
-  if settings.respond_to? :public_folder
-    set :public_folder, File::join($top_srcdir, 'public')
-  else
-    set :public, File::join($top_srcdir, 'public')
-  end
-  # Try to load the driver on startup to fail early if there are issues
-  driver
-end
-
-configure :production do
-  use Rack::SyslogLogger
-  set :logger, SyslogFile.new
-  disable :logging
-  enable :show_errors
-  enable :dump_errors
-end
-
-configure :development do
-  # So we can just use puts for logging
-  set :raise_errors => false
-  set :show_exceptions, false
-  $stdout.sync = true
-  $stderr.sync = true
-end
-
-# You could use $API_HOST environment variable to change your hostname to
-# whatever you want (eg. if you running API behind NAT)
-HOSTNAME=ENV['API_HOST'] ? ENV['API_HOST'] : nil
-
-error do
-  report_error
-end
-
-error Deltacloud::ExceptionHandler::ValidationFailure do
-  report_error
-end
-
-before do
-  # Respond with 400, If we don't get a http Host header,
-  halt 400, "Unable to find HTTP Host header" if @env['HTTP_HOST'] == nil
-end
-
-after do
-  headers 'Server' => 'Apache-Deltacloud/' + settings.version
-end
-
-# Redirect to /api
-get '/' do redirect settings.root_url, 301; end
-
-
-# Generate a root route for API docs
-get "#{settings.root_url}/docs\/?" do
-  respond_to do |format|
-    format.html { haml :'docs/index' }
-    format.xml { haml :'docs/index' }
-  end
-end
-
-get "#{settings.root_url}\/?" do
-  if params[:force_auth]
-    return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
-  end
-  @collections = [:drivers] + driver.supported_collections
-  @driver_name = driver.name unless driver.name.to_sym == DRIVER
-  @providers = driver.configured_providers
-  respond_to do |format|
-    format.xml { haml :"api/show" }
-    format.json do
-      { :api => {
-          :version => settings.version,
-          :driver => driver_symbol,
-          :links => entry_points.collect do |l|
-            { :rel => l[0], :href => l[1] }.merge(json_features_for_entrypoint(l))
-          end
-        }
-      }.to_json
-    end
-    format.html { haml :"api/show" }
-  end
-end
-
-post "#{settings.root_url}\/?"  do
-  p = {}
-  ["provider", "driver"].each { |k| p[k] = params[k] if params[k] }
-  p.delete("provider") if p["provider"] == "default"
-  q = p.map { |k,v| "#{k}=#{v}" }.join(";")
-  q = ";" + q unless q.empty?
-  redirect "#{settings.root_url}#{q}", 301
-end
-
-# Rabbit DSL
-
-collection :drivers do
-  global!
-
-  description <<EOS
-List all the drivers supported by this server.
-EOS
-
-  operation :index do
-    description "List all drivers"
-    control do
-      @drivers = settings.drivers
-      respond_to do |format|
-        format.xml { haml :"drivers/index" }
-        format.json { @drivers.to_json }
-        format.html { haml :"drivers/index" }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show details for a driver"
-    param :id,      :string
-    control do
-      @name = params[:id].to_sym
-      if driver_symbol == @name
-        @providers = driver.providers(credentials)  if driver.respond_to? :providers
-      end
-      @driver = settings.drivers[@name]
-      halt 404 unless @driver
-      respond_to do |format|
-        format.xml { haml :"drivers/show" }
-        format.json { @driver.to_json }
-        format.html { haml :"drivers/show" }
-      end
-    end
-  end
-end
-
-collection :realms do
-  description <<END
-  Within a cloud provider a realm represents a boundary containing resources.
-  The exact definition of a realm is left to the cloud provider.
-  In some cases, a realm may represent different datacenters, different continents,
-  or different pools of resources within a single datacenter.
-  A cloud provider may insist that resources must all exist within a single realm in
-  order to cooperate. For instance, storage volumes may only be allowed to be mounted to
-  instances within the same realm.
-END
-
-  operation :index do
-    description <<END
-    Operation will list all available realms. Realms can be filtered using
-    the "architecture" parameter.
-END
-    with_capability :realms
-    param :id,            :string
-    param :architecture,  :string,  :optional,  [ 'i386', 'x86_64' ]
-    control { filter_all(:realms) }
-  end
-
-  #FIXME: It always shows whole list
-  operation :show do
-    description 'Show an realm identified by "id" parameter.'
-    with_capability :realm
-    param :id,           :string, :required
-    control { show(:realm) }
-  end
-
-end
-
-collection :images do
-  description <<END
-  An image is a platonic form of a machine. Images are not directly executable,
-  but are a template for creating actual instances of machines.
-END
-
-  operation :new do
-    description "Form to create a new image resource"
-    param :instance_id, :string,  "An instance from which the new image will be created from"
-    control do
-      @instance = Instance.new( :id => params[:instance_id] )
-      respond_to do |format|
-        format.html { haml :"images/new" }
-      end
-    end
-  end
-
-  operation :index do
-    description <<END
-    The images collection will return a set of all images
-    available to the current use. Images can be filtered using the
-    "owner_id" and "architecture" parameters.
-END
-    with_capability :images
-    param :id,            :string
-    param :architecture,  :string,  :optional
-    control { filter_all(:images) }
-  end
-
-  operation :show do
-    description 'Show an image identified by "id" parameter.'
-    with_capability :image
-    param :id,           :string, :required
-    control { show(:image) }
-  end
-
-  operation :create do
-    description 'Create image from instance'
-    with_capability :create_image
-    param :instance_id, :string, :required
-    control do
-      @image = driver.create_image(credentials, {
-        :id => params[:instance_id],
-        :name => params[:name],
-        :description => params[:description]
-      })
-      status 201  # Created
-      response['Location'] = image_url(@image.id)
-      respond_to do |format|
-        format.xml  { haml :"images/show" }
-        format.json { convert_to_json(:image, @image) }
-        format.html { haml :"images/show" }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Remove specified image from collection"
-    with_capability :destroy_image
-    param :id,    :string,    :required
-    control do
-      driver.destroy_image(credentials, params[:id])
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(images_url) }
-      end
-    end
-  end
-
-end
-
-collection :instance_states do
-  description "The possible states of an instance, and how to traverse between them "
-
-  operation :index do
-    control do
-      @machine = driver.instance_state_machine
-      respond_to do |format|
-        format.xml { haml :'instance_states/show', :layout => false }
-        format.json do
-          out = []
-          @machine.states.each do |state|
-            transitions = state.transitions.collect do |t|
-              t.automatically? ? {:to => t.destination, :auto => 'true'} : {:to => t.destination, :action => t.action}
-            end
-            out << { :name => state, :transitions => transitions }
-          end
-          out.to_json
-        end
-        format.html { haml :'instance_states/show'}
-        format.gv { erb :"instance_states/show" }
-        format.png do
-          # Trick respond_to into looking up the right template for the
-          # graphviz file
-          gv = erb(:"instance_states/show")
-          png =  ''
-          cmd = 'dot -Kdot -Gpad="0.2,0.2" -Gsize="5.0,8.0" -Gdpi="180" -Tpng'
-          Open3.popen3( cmd ) do |stdin, stdout, stderr|
-            stdin.write( gv )
-            stdin.close()
-            png = stdout.read
-          end
-          content_type 'image/png'
-          png
-        end
-      end
-    end
-  end
-end
-
-get "#{settings.root_url}/instances/:id/run" do
-  @instance = driver.instance(credentials, :id => params[:id])
-  respond_to do |format|
-    format.html { haml :"instances/run_command" }
-  end
-end
-
-collection :load_balancers do
-  description "Load balancers"
-
-  operation :new do
-    description "Form to create a new load balancer"
-    control do
-      @realms = driver.realms(credentials)
-      @instances = driver.instances(credentials) if driver_has_feature?(:register_instance, :load_balancers)
-      respond_to do |format|
-        format.html { haml :"load_balancers/new" }
-      end
-    end
-  end
-
-  operation :index do
-    description "List of all active load balancers"
-    control do
-      filter_all :load_balancers
-    end
-  end
-
-  operation :show do
-    description "Show details about given load balancer"
-    param :id,  :string,  :required
-    control { show :load_balancer }
-  end
-
-  operation :create do
-    description "Create a new load balancer"
-    param :name,  :string,  :required
-    param :realm_id,  :string,  :required
-    param :listener_protocol,  :string,  :required, ['HTTP', 'TCP']
-    param :listener_balancer_port,  :string,  :required
-    param :listener_instance_port,  :string,  :required
-    control do
-      @load_balancer = driver.create_load_balancer(credentials, params)
-      status 201  # Created
-      response['Location'] = load_balancer_url(@instance.id)
-      respond_to do |format|
-        format.xml  { haml :"load_balancers/show" }
-        format.json { convert_to_json(:load_balancer, @load_balancer) }
-        format.html { haml :"load_balancers/show" }
-      end
-    end
-  end
-
-  operation :register, :method => :post, :member => true do
-    description "Add instance to loadbalancer"
-    param :id,  :string,  :required
-    param :instance_id, :string,  :required
-    control do
-      driver.lb_register_instance(credentials, params)
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(load_balancer_url(params[:id])) }
-      end
-    end
-  end
-
-  operation :unregister, :method => :post, :member => true do
-    description "Remove instance from loadbalancer"
-    param :id,  :string,  :required
-    param :instance_id, :string,  :required
-    control do
-      driver.lb_unregister_instance(credentials, params)
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(load_balancer_url(params[:id])) }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Destroy given load balancer"
-    param :id,  :string,  :required
-    control do
-      driver.destroy_load_balancer(credentials, params[:id])
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(load_balancers_url) }
-      end
-    end
-  end
-
-end
-
-
-collection :instances do
-  description <<END
-  An instance is a concrete machine realized from an image.
-  The images collection may be obtained by following the link from the primary entry-point.
-END
-
-  operation :new do
-    description "Form for creating a new instance resource"
-    param :image_id,  :string,  "Image from which will be the new instance created from"
-    param :realm_id,  :string, :optional
-    if driver_has_feature? :authentication_key
-      param :authentication_key, :string, :optional
-    end
-    if driver_has_feature? :firewalls
-      param :firewalls, :string, :optional
-    end
-    control do
-      @instance = Instance.new( { :id=>params[:id], :image_id=>params[:image_id] } )
-      @image   = Image.new( :id => params[:image_id] )
-      @hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
-      @realms = [Realm.new(:id => params[:realm_id])] if params[:realm_id]
-      @realms ||= driver.realms(credentials)
-      @keys = driver.keys(credentials) if driver_has_feature?(:authentication_key)
-      @firewalls = driver.firewalls(credentials) if driver_has_feature?(:firewalls)
-      respond_to do |format|
-        format.html do
-          haml :'instances/new'
-        end
-      end
-    end
-  end
-
-  operation :index do
-    description "List all instances."
-    with_capability :instances
-    param :id,            :string,  :optional
-    param :state,         :string,  :optional
-    control { filter_all(:instances) }
-  end
-
-  operation :show do
-    description 'Show an instance identified by "id" parameter.'
-    with_capability :instance
-    param :id,           :string, :required
-    control { show(:instance) }
-  end
-
-  operation :create do
-    description "Create a new instance."
-    with_capability :create_instance
-    param :image_id,     :string, :required
-    param :realm_id,     :string, :optional
-    param :hwp_id,       :string, :optional
-    control do
-      @instance = driver.create_instance(credentials, params[:image_id], params)
-      if @instance.kind_of? Array
-        @elements = @instance
-        action_handler = "index"
-      else
-        response['Location'] = instance_url(@instance.id)
-        action_handler = "show"
-      end
-      status 201  # Created
-      respond_to do |format|
-        format.xml  { haml :"instances/#{action_handler}" }
-        format.json do
-          if @elements
-            convert_to_json(:instances, @elements)
-          else
-            convert_to_json(:instance, @instance)
-          end
-        end
-        format.html do
-          if @elements
-            haml :"instances/index"
-          elsif @instance and @instance.id
-            response['Location'] = instance_url(@instance.id)
-            haml :"instances/show"
-          else
-            redirect instances_url
-          end
-        end
-      end
-    end
-  end
-
-  operation :reboot, :method => :post, :member => true do
-    description "Reboot a running instance."
-    with_capability :reboot_instance
-    param :id,           :string, :required
-    control { instance_action(:reboot) }
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start an instance."
-    with_capability :start_instance
-    param :id,           :string, :required
-    control { instance_action(:start) }
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop a running instance."
-    with_capability :stop_instance
-    param :id,           :string, :required
-    control { instance_action(:stop) }
-  end
-
-  operation :destroy do
-    description "Destroy an instance."
-    with_capability :destroy_instance
-    param :id,           :string, :required
-    control { instance_action(:destroy) }
-  end
-
-  operation :run, :method => :post, :member => true do
-    description <<END
-  Run command on instance. Either password or private key must be send
-  in order to execute command. Authetication method should be advertised
-  in instance.
-END
-    with_capability :run_on_instance
-    param :id,          :string,  :required
-    param :cmd,         :string,  :required, [], "Shell command to run on instance"
-    param :private_key, :string,  :optional, [], "Private key in PEM format for authentication"
-    param :password,    :string,  :optional, [], "Password used for authentication"
-    control do
-      @output = driver.run_on_instance(credentials, params)
-      respond_to do |format|
-        format.xml { haml :"instances/run" }
-        format.html { haml :"instances/run" }
-      end
-    end
-  end
-end
-
-collection :metrics do
-
-  operation :index do
-    with_capability :metrics
-    control { filter_all(:metrics) }
-  end
-
-  operation :show do
-    with_capability :metrics
-    param :id,  :string,  :required
-    control { show :metric }
-  end
-
-end
-
-collection :hardware_profiles do
-  description <<END
- A hardware profile represents a configuration of resources upon which a
- machine may be deployed. It defines aspects such as local disk storage,
- available RAM, and architecture. Each provider is free to define as many
- (or as few) hardware profiles as desired.
-END
-
-  operation :index do
-    description "List of available hardware profiles."
-    with_capability :hardware_profiles
-    param :id,          :string
-    param :architecture,  :string,  :optional,  [ 'i386', 'x86_64' ]
-    control do
-        @profiles = driver.hardware_profiles(credentials, params)
-        @profiles = order_hardware_profiles(@profiles)
-        respond_to do |format|
-          format.xml  { haml :'hardware_profiles/index' }
-          format.html  { haml :'hardware_profiles/index' }
-          format.json { convert_to_json(:hardware_profile, @profiles) }
-        end
-    end
-  end
-
-  operation :show do
-    description "Show specific hardware profile."
-    with_capability :hardware_profile
-    param :id,          :string,    :required
-    control do
-      @profile =  driver.hardware_profile(credentials, params[:id])
-      if @profile
-        respond_to do |format|
-          format.xml { haml :'hardware_profiles/show', :layout => false }
-          format.html { haml :'hardware_profiles/show' }
-          format.json { convert_to_json(:hardware_profile, @profile) }
-        end
-      else
-        report_error(404)
-      end
-    end
-  end
-
-end
-
-collection :storage_snapshots do
-  description "Storage snapshots description here"
-
-  operation :new do
-    description "A form to create a new storage snapshot"
-    control do
-      respond_to do |format|
-        format.html { haml :"storage_snapshots/new" }
-      end
-    end
-  end
-
-  operation :index do
-    description "List of storage snapshots."
-    with_capability :storage_snapshots
-    param :id,            :string
-    control { filter_all(:storage_snapshots) }
-  end
-
-  operation :show do
-    description "Show storage snapshot."
-    with_capability :storage_snapshot
-    param :id,          :string,    :required
-    control { show(:storage_snapshot) }
-  end
-
-  operation :create do
-    description "Create a new snapshot from volume"
-    with_capability :create_storage_snapshot
-    param :volume_id, :string,  :required
-    control do
-      @storage_snapshot = driver.create_storage_snapshot(credentials, params)
-      status 201  # Created
-      response['Location'] = storage_snapshot_url(@storage_snapshot.id)
-      show(:storage_snapshot)
-    end
-  end
-
-  operation :destroy do
-    description "Delete storage snapshot"
-    with_capability :destroy_storage_snapshot
-    param :id,  :string,  :required
-    control do
-      driver.destroy_storage_snapshot(credentials, params)
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(storage_snapshots_url) }
-      end
-    end
-  end
-end
-
-collection :storage_volumes do
-  description "Storage volumes description here"
-
-  operation :new do
-    description "A form to create a new storage volume"
-    control do
-      respond_to do |format|
-        format.html { haml :"storage_volumes/new" }
-      end
-    end
-  end
-
-  operation :index do
-    description "List of storage volumes."
-    with_capability :storage_volumes
-    param :id,            :string
-    control { filter_all(:storage_volumes) }
-  end
-
-  operation :show do
-    description "Show storage volume."
-    with_capability :storage_volume
-    param :id,          :string,    :required
-    control { show(:storage_volume) }
-  end
-
-  operation :create do
-    description "Create a new storage volume"
-    with_capability :create_storage_volume
-    param :snapshot_id, :string,  :optional
-    param :capacity,    :string,  :optional
-    param :realm_id,    :string,  :optional
-    control do
-      @storage_volume = driver.create_storage_volume(credentials, params)
-      status 201
-      response['Location'] = storage_volume_url(@storage_volume.id)
-      respond_to do |format|
-        format.xml  { haml :"storage_volumes/show" }
-        format.html { haml :"storage_volumes/show" }
-        format.json { convert_to_json(:storage_volume, @storage_volume) }
-      end
-    end
-  end
-
-  operation :attach_instance, :method=>:get, :member=>true  do
-    description "A form to attach a storage volume to an instance"
-    control do
-      @instances = driver.instances(credentials)
-      respond_to do |format|
-        format.html{ haml :"storage_volumes/attach"}
-      end
-    end
-  end
-
-  operation :attach, :method => :post, :member => true do
-    description "Attach storage volume to instance"
-    with_capability :attach_storage_volume
-    param :id,         :string,  :required
-    param :instance_id,:string,  :required
-    param :device,     :string,  :required
-    control do
-      @storage_volume = driver.attach_storage_volume(credentials, params)
-      status 202
-      respond_to do |format|
-        format.html { redirect(storage_volume_url(params[:id]))}
-        format.xml  { haml :"storage_volumes/show" }
-        format.json { convert_to_json(:storage_volume, @storage_volume) }
-      end
-    end
-  end
-
-  operation :detach, :method => :post, :member => true do
-    description "Detach storage volume to instance"
-    with_capability :detach_storage_volume
-    param :id,         :string,  :required
-    control do
-      volume = driver.storage_volume(credentials, :id => params[:id])
-      @storage_volume =  driver.detach_storage_volume(credentials, :id => volume.id, :instance_id => volume.instance_id, :device => volume.device)
-      status 202
-      respond_to do |format|
-        format.html { redirect(storage_volume_url(params[:id]))}
-        format.xml  { haml :"storage_volumes/show" }
-        format.json { convert_to_json(:storage_volume, @storage_volume) }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Destroy storage volume"
-    with_capability :destroy_storage_volume
-    param :id,          :string,  :optional
-    control do
-      driver.destroy_storage_volume(credentials, params)
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(storage_volumes_url) }
-      end
-    end
-  end
-
-end
-
-collection :keys do
-  description "Instance authentication credentials."
-
-  operation :new do
-    description "A form to create a new key resource"
-    control do
-      respond_to do |format|
-        format.html { haml :"keys/new" }
-      end
-    end
-  end
-
-  operation :index do
-    description "List all available credentials which could be used for instance authentication."
-    with_capability :keys
-    control do
-      filter_all :keys
-    end
-  end
-
-  operation :show do
-    description "Show details about given instance credential."
-    with_capability :key
-    param :id,  :string,  :required
-    control { show :key }
-  end
-
-  operation :create do
-    description "Create a new instance credential if backend supports this."
-    with_capability :create_key
-    param :name,  :string,  :required
-    control do
-      @key = driver.create_key(credentials, { :key_name => params[:name] })
-      status 201
-      response['Location'] = key_url(@key.id)
-      respond_to do |format|
-        format.xml  { haml :"keys/show", :ugly => true }
-        format.html { haml :"keys/show" }
-        format.json { convert_to_json(:key, @key)}
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Destroy given instance credential if backend supports this."
-    with_capability :destroy_key
-    param :id,  :string,  :required
-    control do
-      driver.destroy_key(credentials, { :id => params[:id]})
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(keys_url) }
-      end
-    end
-  end
-
-end
-
-#get html form for creating a new blob
-
-# The URL for getting the new blob form for the HTML UI looks like the URL
-# for getting the details of an existing blob. To make collisions less
-# likely, we use a name for the form that will rarely be the name of an
-# existing blob
-NEW_BLOB_FORM_ID = "new_blob_form_d15cfd90"
-
-get "#{settings.root_url}/buckets/:bucket/#{NEW_BLOB_FORM_ID}" do
-  @bucket_id = params[:bucket]
-  respond_to do |format|
-    format.html {haml :"blobs/new"}
-  end
-end
-
-collection :buckets do
-  description "Cloud Storage buckets - aka buckets|directories|folders"
-
-  collection :blobs do
-    description "Blobs associated with given bucket"
-
-    operation :show do
-      description "Display blob"
-      control do
-        @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
-        if @blob
-          respond_to do |format|
-            format.xml { haml :"blobs/show" }
-            format.html { haml :"blobs/show" }
-            format.json { convert_to_json(:blob, @blob) }
-          end
-        else
-          report_error(404)
-        end
-      end
-
-    end
-
-    operation :create do
-      description "Create new blob"
-      param :blob_id,  :string,  :required
-      param :blob_data, :hash, :required
-      control do
-        bucket_id = params[:bucket]
-        blob_id = params['blob_id']
-        blob_data = params['blob_data']
-        user_meta = {}
-        #metadata from params (i.e., passed by http form post, e.g. browser)
-        max = params[:meta_params]
-        if(max)
-          (1..max.to_i).each do |i|
-            key = params[:"meta_name#{i}"]
-            key = "HTTP_X_Deltacloud_Blobmeta_#{key}"
-            value = params[:"meta_value#{i}"]
-            user_meta[key] = value
-          end
-        end
-        @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
-        respond_to do |format|
-          format.xml { haml :"blobs/show" }
-          format.html { haml :"blobs/show"}
-          format.json {convert_to_json(:blob, @blob)}
-        end
-      end
-    end
-
-    operation :destroy do
-      description "Destroy given blob"
-      control do
-        bucket_id = params[:bucket]
-        blob_id = params[:blob]
-        driver.delete_blob(credentials, bucket_id, blob_id)
-        status 204
-        respond_to do |format|
-          format.xml
-          format.json
-          format.html { redirect(bucket_url(bucket_id)) }
-        end
-      end
-    end
-
-    operation :stream, :member => true, :standard => true, :method => :put do
-      description "Stream new blob data into the blob"
-      control do
-        if(env["BLOB_SUCCESS"]) #ie got a 200ok after putting blob
-          content_type = env["CONTENT_TYPE"]
-          content_type ||=  ""
-          @blob = driver.blob(credentials, {:id => params[:blob],
-                                            'bucket' => params[:bucket]})
-          respond_to do |format|
-            format.xml { haml :"blobs/show" }
-            format.html { haml :"blobs/show" }
-            format.json { convert_to_json(:blob, @blob) }
-          end
-        elsif(env["BLOB_FAIL"])
-          report_error(500) #OK?
-        else # small blobs - < 112kb dont hit the streaming monkey patch - use 'normal' create_blob
-          # also, if running under webrick don't hit the streaming patch (Thin specific)
-          bucket_id = params[:bucket]
-          blob_id = params[:blob]
-          temp_file = Tempfile.new("temp_blob_file")
-          temp_file.write(env['rack.input'].read)
-          temp_file.flush
-          content_type = env['CONTENT_TYPE'] || ""
-          blob_data = {:tempfile => temp_file, :type => content_type}
-          user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
-          @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
-          temp_file.delete
-          respond_to do |format|
-            format.xml { haml :"blobs/show" }
-            format.html { haml :"blobs/show" }
-            format.json { convert_to_json(:blob, @blob) }
-          end
-        end
-      end
-    end
+require 'sinatra/base'
+require 'sinatra/rabbit'
 
-    operation :metadata, :member => true, :standard => true, :method => :head do
-      description "Get blob metadata"
-      control do
-        @blob_id = params[:blob]
-        @blob_metadata = driver.blob_metadata(credentials, {:id => params[:blob], 'bucket' => params[:bucket]})
-        if @blob_metadata
-          @blob_metadata.each do |k,v|
-            headers["X-Deltacloud-Blobmeta-#{k}"] = v
-          end
-          status 204
-          respond_to do |format|
-            format.xml
-            format.json
-          end
-        else
-          report_error(404)
-        end
-      end
-    end
+require_relative '../sinatra'
+require_relative './models'
+require_relative './drivers'
+require_relative './helpers'
+require_relative './collections'
 
-    operation :update, :member => true, :method => :post do
-      description "Update blob metadata"
-      control do
-        meta_hash = BlobHelper::extract_blob_metadata_hash(request.env)
-        success = driver.update_blob_metadata(credentials, {'bucket'=>params[:bucket], :id =>params[:blob], 'meta_hash' => meta_hash})
-        if(success)
-          meta_hash.each do |k,v|
-            headers["X-Deltacloud-Blobmeta-#{k}"] = v
-          end
-          status 204
-          respond_to do |format|
-            format.xml
-            format.json
-          end
-        else
-          report_error(404) #FIXME is this the right error code?
-        end
-      end
-    end
+module Deltacloud
+  class API < Collections::Base
 
-    operation :content, :member => true, :method => :get do
-      description "Download blob content"
-      control do
-        @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
-        if @blob
-          params['content_length'] = @blob.content_length
-          params['content_type'] = @blob.content_type
-          params['content_disposition'] = "attachment; filename=#{@blob.id}"
-          BlobStream.call(env, credentials, params)
-        else
-          report_error(404)
-        end
-      end
-    end
+    # Enable logging
+    use Rack::CommonLogger
+    use Rack::Date
+    use Rack::ETag
+    use Rack::MatrixParams
+    use Rack::DriverSelect
+    use Rack::Accept
+    use Rack::MediaType
 
-  end
+    include Deltacloud::Helpers
+    include Deltacloud::Collections
 
-  operation :new do
-    description "A form to create a new bucket resource"
-    control do
-      respond_to do |format|
-        format.html { haml :"buckets/new" }
+    get Deltacloud[:root_url] + '/?' do
+      if params[:force_auth]
+        return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
       end
-    end
-  end
-
-  operation :index do
-    description "List buckets associated with this account"
-    with_capability :buckets
-    param :id,        :string
-    param :name,      :string
-    param :size,      :string
-    control { filter_all(:buckets) }
-  end
-
-  operation :show do
-    description "Show bucket"
-    with_capability :bucket
-    param :id,        :string
-    control { show(:bucket) }
-  end
-
-  operation :create do
-    description "Create a new bucket (POST /api/buckets)"
-    with_capability :create_bucket
-    param :name,      :string,    :required
-    control do
-      @bucket = driver.create_bucket(credentials, params[:name], params)
-      status 201
-      response['Location'] = bucket_url(@bucket.id)
       respond_to do |format|
-        format.xml  { haml :"buckets/show" }
-        format.json { convert_to_json(:bucket, @bucket) }
-        format.html do
-          redirect bucket_url(@bucket.id) if @bucket and @bucket.id
-          redirect buckets_url
-        end
+        format.xml { haml :"api/show" }
+        format.json { xml_to_json :"api/show" }
+        format.html { haml :"api/show" }
       end
     end
-  end
 
-  operation :destroy do
-    description "Delete a bucket by name - bucket must be empty"
-    with_capability :delete_bucket
-    param :id,    :string,    :required
-    control do
-      driver.delete_bucket(credentials, params[:id], params)
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html {  redirect(buckets_url) }
-      end
-    end
   end
-
 end
 
-get "#{settings.root_url}/addresses/:id/associate" do
-  @instances = driver.instances(credentials)
-  @address = Address::new(:id => params[:id])
-  respond_to do |format|
-    format.html { haml :"addresses/associate" }
-  end
-end
-
-collection :addresses do
-  description "Manage IP addresses"
-
-  operation :index do
-    description "List IP addresses assigned to your account."
-    with_capability :addresses
-    control do
-      filter_all :addresses
-    end
-  end
-
-  operation :show do
-    description "Show details about IP addresses specified by given ID"
-    with_capability :address
-    param :id,  :string,  :required
-    control { show :address }
-  end
-
-  operation :create do
-    description "Acquire a new IP address for use with your account."
-    with_capability :create_address
-    control do
-      @address = driver.create_address(credentials, {})
-      status 201    # Created
-      response['Location'] = address_url(@address.id)
-      respond_to do |format|
-        format.xml  { haml :"addresses/show", :ugly => true }
-        format.html { haml :"addresses/_address", :layout => false }
-        format.json { convert_to_json(:address, @address) }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Release an IP address associated with your account"
-    with_capability :destroy_address
-    param :id,  :string,  :required
-    control do
-      driver.destroy_address(credentials, { :id => params[:id]})
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(addresses_url) }
-      end
-    end
-  end
-
-  operation :associate, :method => :post, :member => true do
-    description "Associate an IP address to an instance"
-    with_capability :associate_address
-    param :id, :string, :required
-    param :instance_id, :string, :required
-    control do
-      driver.associate_address(credentials, { :id => params[:id], :instance_id => params[:instance_id]})
-      status 202   # Accepted
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(address_url(params[:id])) }
-      end
-    end
-  end
-
-  operation :disassociate, :method => :post, :member => true do
-    description "Disassociate an IP address from an instance"
-    with_capability :associate_address
-    param :id, :string, :required
-    control do
-      driver.disassociate_address(credentials, { :id => params[:id] })
-      status 202   # Accepted
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html { redirect(address_url(params[:id])) }
-      end
-    end
-  end
-
-end
-
-#delete a firewall rule
-delete '/api/firewalls/:firewall/:rule' do
-  opts = {}
-  opts[:firewall] = params[:firewall]
-  opts[:rule_id] = params[:rule]
-  driver.delete_firewall_rule(credentials, opts)
-  status 204
-  respond_to do |format|
-    format.xml
-    format.json
-    format.html {redirect firewall_url(params[:firewall])}
-  end
-end
-
-#FIREWALLS
-collection :firewalls do
-  description "Allow user to define firewall rules for an instance (ec2 security groups) eg expose ssh access [port 22, tcp]."
-
-  operation :new do
-    description "A form to create a new firewall resource"
-    control do
-      respond_to do |format|
-        format.html { haml :"firewalls/new" }
-      end
-    end
-  end
-
-  operation :new_rule, :form => true, :member => true, :method => :get do
-    description "A form to create a new firewall rule"
-    param :id,  :string,  :required
-    control do
-      @firewall_name = params[:id]
-      respond_to do |format|
-        format.html {haml :"firewalls/new_rule" }
-      end
-    end
-  end
-
-  operation :index do
-    description 'List all firewalls'
-    with_capability :firewalls
-    control { filter_all(:firewalls) }
-  end
-
-  operation :show do
-    description 'Show details for a specific firewall - list all rules'
-    with_capability :firewall
-    param :id,            :string,    :required
-    control { show(:firewall) }
-  end
-
-  operation :create do
-    description 'Create a new firewall'
-    with_capability :create_firewall
-    param :name,          :string,    :required
-    param :description,   :string,    :required
-    control do
-      @firewall = driver.create_firewall(credentials, params )
-      status 201  # Created
-      response['Location'] = firewall_url(@firewall.id)
-      respond_to do |format|
-        format.xml  { haml :"firewalls/show" }
-        format.html { haml :"firewalls/show" }
-        format.json { convert_to_json(:firewall, @firewall) }
-      end
-    end
-  end
-
-  operation :destroy do
-    description 'Delete a specified firewall - error if firewall has rules'
-    with_capability :delete_firewall
-    param :id,            :string,    :required
-    control do
-      driver.delete_firewall(credentials, params)
-      status 204
-      respond_to do |format|
-        format.xml
-        format.json
-        format.html {  redirect(firewalls_url) }
-      end
-    end
-  end
-
-  #create a new firewall rule - POST /api/firewalls/:firewall/rules
-  operation :rules, :method => :post, :member => true do
-    description 'Create a new firewall rule for the specified firewall'
-    param :id,  :required, :string, [],  "Name of firewall in which to apply this rule"
-    param :protocol,  :required, :string, ['tcp','udp','icmp'], "Transport layer protocol for the rule"
-    param :port_from, :required, :string, [], "Start of port range for the rule"
-    param :port_to,   :required, :string, [], "End of port range for the rule"
-    with_capability :create_firewall_rule
-    control do
-      #source IPs from params
-      addresses =  params.inject([]){|result,current| result << current.last unless current.grep(/^ip[-_]address/i).empty?; result}
-      #source groups from params
-      groups = {}
-      max_groups  = params.select{|k,v| k=~/^group/}.size/2
-      for i in (1..max_groups) do
-        groups.merge!({params["group#{i}"]=>params["group#{i}owner"]})
-      end
-      params['addresses'] = addresses
-      params['groups'] = groups
-      if addresses.empty? && groups.empty?
-        raise Deltacloud::ExceptionHandler::ValidationFailure.new(
-          StandardError.new("No sources. Specify at least one source ip_address or group")
-        )
-      end
-      driver.create_firewall_rule(credentials, params)
-      @firewall = driver.firewall(credentials, {:id => params[:id]})
-      status 201
-      respond_to do |format|
-        format.xml  { haml :"firewalls/show" }
-        format.html { haml :"firewalls/show" }
-        format.json { convert_to_json(:firewall, @firewall) }
-      end
-    end
-  end
-
-end
-- 
1.7.10.1


[PATCH core 39/51] SBC: Fixed Cucumber tests for the SBC driver

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 tests/sbc/support/env.rb |   18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/tests/sbc/support/env.rb b/tests/sbc/support/env.rb
index fe27329..a7bf373 100644
--- a/tests/sbc/support/env.rb
+++ b/tests/sbc/support/env.rb
@@ -1,20 +1,16 @@
 require 'rubygems'
 require 'nokogiri'
-
-SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
-$top_srcdir = SERVER_DIR
-$:.unshift File::join($top_srcdir, 'lib')
-Dir.chdir(SERVER_DIR)
-
-API_VERSION = "9.9.9"
-API_ROOT_URL = "/api"
+require 'rack/test'
 
 ENV['API_DRIVER'] = 'sbc'
-ENV.delete('API_VERBOSE')
 
-load File.join($top_srcdir, 'lib', 'deltacloud', 'server.rb')
+load File.join(File.dirname(__FILE__), '..', '..', '..', 'server', 'lib', 'deltacloud_rack.rb')
 
-require 'rack/test'
+Deltacloud::configure do |server|
+  server.root_url '/api'
+  server.version '0.5.0'
+  server.klass 'Deltacloud::API'
+end.require_frontend!
 
 module Rack
   module Test
-- 
1.7.10.1


[PATCH core 26/51] FGCP: Fixed configuration of providers

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/config/drivers/fgcp.yaml |    1 +
 1 file changed, 1 insertion(+)

diff --git a/server/config/drivers/fgcp.yaml b/server/config/drivers/fgcp.yaml
index 8c24f66..838b710 100644
--- a/server/config/drivers/fgcp.yaml
+++ b/server/config/drivers/fgcp.yaml
@@ -4,6 +4,7 @@
   :username: Username
   :password: Secret Key Password of User Certificate
   :entrypoints:
+    default:
       jp: https://api.oviss.jp.fujitsu.com/ovissapi/endpoint
       au: https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint
       sg: https://api.globalcloud.sg.fujitsu.com/ovissapi/endpoint
-- 
1.7.10.1


[PATCH core 29/51] Test: Fixed Ruby 1.9 compatibility issue with 'case' statement.

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/tests/drivers/mock/common.rb |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/server/tests/drivers/mock/common.rb b/server/tests/drivers/mock/common.rb
index 2b96711..2610965 100644
--- a/server/tests/drivers/mock/common.rb
+++ b/server/tests/drivers/mock/common.rb
@@ -1,3 +1,6 @@
+ENV['API_USERNAME'] = 'mockuser'
+ENV['API_PASSWORD'] = 'mockpassword'
+
 load File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'deltacloud_rack.rb')
 
 Deltacloud::configure do |server|
-- 
1.7.10.1


[PATCH core 35/51] Core: Driver constraints, like :max_length are now advertised correctly

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers/base_driver.rb          |   11 +++++++++++
 server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb |   11 +++++++----
 server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb   |   12 ++++--------
 server/views/api/show.xml.haml                        |    2 ++
 4 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb
index 3d4c75d..9913c27 100644
--- a/server/lib/deltacloud/drivers/base_driver.rb
+++ b/server/lib/deltacloud/drivers/base_driver.rb
@@ -42,9 +42,20 @@ module Deltacloud
 
     def self.feature(collection, feature_name)
       return if has_feature?(collection, feature_name)
+      constraints[collection] ||= {}
+      constraints[collection][feature_name] ||= {}
+      constraints[collection][feature_name].merge!(yield) if block_given?
       features << { collection => feature_name }
     end
 
+    def self.constraints(opts={})
+      if opts[:collection] and opts[:feature]
+        return [] unless @constraints.has_key? opts[:collection]
+        return @constraints[opts[:collection]][opts[:feature]]
+      end
+      @constraints ||= {}
+    end
+
     def self.has_feature?(collection, feature_name)
       features.any? { |f| (f.values.first == feature_name) && (f.keys.first == collection) }
     end
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
index ee08afe..6469312 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
@@ -32,13 +32,16 @@ module Deltacloud
 
 class GogridDriver < Deltacloud::BaseDriver
 
-  feature :instances, :authentication_password
-  feature :instances, :sandboxing
   feature :instances, :user_name do
-    constraint :max_length, 20
+    { :max_length => 20 }
   end
 
-  USER_NAME_MAX = feature(:instances, :user_name).constraints[:max_length]
+  feature :instances, :authentication_password
+  feature :instances, :sandboxing
+
+  define_hardware_profile 'default'
+
+  USER_NAME_MAX = constraints(:collection => :instances, :feature => :user_name)[:max_length]
 
   def hardware_profiles(credentials, opts={})
     client = new_client(credentials)
diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
index f138f03..e93c631 100644
--- a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
+++ b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
@@ -22,16 +22,12 @@ module Deltacloud
 
 class RhevmDriver < Deltacloud::BaseDriver
 
-  Sinatra::Rabbit::InstancesCollection.features do
-    feature :user_name, :for => :instances do
-      constrain :max_length, 50
-    end
-  end
-
   feature :instances, :user_data
-  feature :images, :user_name
+  feature :instances, :user_name do
+    { :max_length => 50 }
+  end
 
-  USER_NAME_MAX = Sinatra::Rabbit::InstancesCollection.feature(:user_name).constraints[:max_length]
+  USER_NAME_MAX = constraints(:collection => :instances, :feature => :user_name)[:max_length]
 
   # FIXME: These values are just for ilustration
   # Also I choosed 'SERVER' and 'DESKTOP' names
diff --git a/server/views/api/show.xml.haml b/server/views/api/show.xml.haml
index ad2df09..4ba8168 100644
--- a/server/views/api/show.xml.haml
+++ b/server/views/api/show.xml.haml
@@ -4,3 +4,5 @@
     %link{ :rel => c.collection_name, :href => self.send(:"#{c.collection_name}_url")}
       - c.features.select { |f| driver.class.has_feature?(c.collection_name, f.name) }.each do |f|
         %feature{ :name => f.name }
+          - driver.class.constraints(:collection => c.collection_name, :feature => f.name).each do |name, value|
+            %constraint{ :name => name }=value
-- 
1.7.10.1


Re: [PATCH core 50/51] Core: Updated links and installation instructions in README.md

Posted by David Lutterkort <lu...@redhat.com>.
On Mon, 2012-05-21 at 12:07 +0200, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>
> 

You can drop this patch - I just committed a fix for this and some other
incubation leftovers.

David



[PATCH core 50/51] Core: Updated links and installation instructions in README.md

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/README.md |   12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/server/README.md b/server/README.md
index aacc0af..750ebf7 100644
--- a/server/README.md
+++ b/server/README.md
@@ -6,14 +6,14 @@ Deltacloud protects yourapps from cloud API changes and incompatibilities,
 so you can concentrate on managing cloud instances the way you want.
 
 You can find more documentation at the Deltacloud web site at:
-[incubator.apache.org/deltacloud](http://incubator.apache.org/deltacloud/)
+[deltacloud.apache.org](http://deltacloud.apache.org/)
 
 Prerequisites
 -------------
 
 Deltacloud Core depends on a number of other Ruby libraries. The easiest
 way to install them is to either install the deltacloud-core package from
-your distribution is repository, e.g. `yum install deltacloud-core` on
+your distribution is repository, e.g. `yum install deltacloud-core-all` on
 Fedora, or install the gem with `gem install deltacloud-core`.
 
 If you do not want to do that, have a look at the dependencies in the gem
@@ -21,9 +21,7 @@ spec for deltacloud-core and install them manually from git repository:
 
     $ mkdir deltacloud
     $ cd deltacloud
-    $ git svn init -s https://svn.apache.org/repos/asf/incubator/deltacloud
-    $ git svn fetch --log-window-size 10000
-    $ git clone git://git.apache.org/deltacloud.git core
+    $ git clone https://git-wip-us.apache.org/repos/asf/deltacloud.git core
 
 Running
 -------
@@ -45,7 +43,7 @@ set _format_ to URLs, they should simply set the _Accept_ header appropriately.
 Some operations require authentication. For the mock driver, the username
 and password are *mockuser* and *mockpassword*. A current list of drivers
 and what kind of credentials they need can be found at
-Deltacloud Incubator site (http://incubator.apache.org/deltacloud/drivers.html)
+Deltacloud Incubator site (http://deltacloud.apache.org/deltacloud/drivers.html)
 
 Happy hacking - and do not forget to send patches to the mailing list (see
 [deltacloud-devel](https://fedorahosted.org/mailman/listinfo/deltacloud-devel) or
@@ -54,7 +52,7 @@ You could send patches using `git format-patch master` and then `git send-email
 --thread`. Example _git/.config_ file:
 
     [sendemail]
-        to = deltacloud-dev@incubator.apache.org
+        to = dev@deltacloud.apache.org
         signedoffbycc=no
         chainreplyto=no
         smtpserver=YOUR_SMTP_SERVER_HERE
-- 
1.7.10.1


[PATCH core 45/51] Core: Replaced 'require' with 'require_relative' to keep loading of core extensions working under MRI 1.9

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/core_ext.rb |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/server/lib/deltacloud/core_ext.rb b/server/lib/deltacloud/core_ext.rb
index b54df66..edaaa00 100644
--- a/server/lib/deltacloud/core_ext.rb
+++ b/server/lib/deltacloud/core_ext.rb
@@ -14,8 +14,8 @@
 # under the License.
 #
 
-require 'deltacloud/core_ext/array'
-require 'deltacloud/core_ext/hash'
-require 'deltacloud/core_ext/integer'
-require 'deltacloud/core_ext/proc'
-require 'deltacloud/core_ext/string'
+require_relative './core_ext/array'
+require_relative './core_ext/hash'
+require_relative './core_ext/integer'
+require_relative './core_ext/proc'
+require_relative './core_ext/string'
-- 
1.7.10.1


[PATCH core 18/51] Core: Backported the 'metrics' collection from current Deltacloud

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/metrics.rb |   27 ++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 server/lib/deltacloud/collections/metrics.rb

diff --git a/server/lib/deltacloud/collections/metrics.rb b/server/lib/deltacloud/collections/metrics.rb
new file mode 100644
index 0000000..acc951d
--- /dev/null
+++ b/server/lib/deltacloud/collections/metrics.rb
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Metrics < Base
+
+    collection :metrics do
+      description 'Metrics provide monitoring for the cloud resources'
+
+      standard_index_operation
+      standard_show_operation
+
+    end
+  end
+end
-- 
1.7.10.1


[PATCH core 51/51] Adds ordering of hardware profiles returned from the Provider. Ordering is first by cpu and then by memory. Addresses JIRA DTACLOUD_208 Note: This patch was backported from non-modular

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>

https://issues.apache.org/jira/browse/DTACLOUD-208

Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/helpers/deltacloud_helper.rb |   11 +++++++++++
 server/views/hardware_profiles/index.html.haml     |    2 +-
 server/views/hardware_profiles/index.xml.haml      |    2 +-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb b/server/lib/deltacloud/helpers/deltacloud_helper.rb
index ed3e57d..5806d15 100644
--- a/server/lib/deltacloud/helpers/deltacloud_helper.rb
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -266,6 +266,17 @@ module Deltacloud::Helpers
       end
     end
 
+    def order_hardware_profiles(profiles)
+      #have to deal with opaque hardware profiles
+      uncomparables = profiles.select{|x| x.cpu.nil? or x.memory.nil? }
+      if uncomparables.empty?
+        profiles.sort_by{|a| [a.cpu.default, a.memory.default] }
+      else
+        (profiles - uncomparables).sort_by{|a| [a.cpu.default, a.memory.default] } + uncomparables
+      end
+    end
+
+
     private
     def hardware_property_unit(prop)
       u = ::Deltacloud::HardwareProfile::unit(prop)
diff --git a/server/views/hardware_profiles/index.html.haml b/server/views/hardware_profiles/index.html.haml
index 59d43eb..011e80f 100644
--- a/server/views/hardware_profiles/index.html.haml
+++ b/server/views/hardware_profiles/index.html.haml
@@ -3,7 +3,7 @@
 
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview, :'data-inset' => :true }
-    - for profile in @hardware_profiles
+    - for profile in order_hardware_profiles(@hardware_profiles)
       %li{ :'data-theme' => 'c'}
         %a{ :href => hardware_profile_url(profile.name)}
           %img{ :class => 'ui-link-thumb', :src => '/images/profile.png'}
diff --git a/server/views/hardware_profiles/index.xml.haml b/server/views/hardware_profiles/index.xml.haml
index 25e0496..9292c5b 100644
--- a/server/views/hardware_profiles/index.xml.haml
+++ b/server/views/hardware_profiles/index.xml.haml
@@ -1,4 +1,4 @@
 !!! XML
 %hardware_profiles
-  - @hardware_profiles.each do |prof|
+  - order_hardware_profiles(@hardware_profiles).each do |prof|
     = haml :'hardware_profiles/show', :locals => { :@hardware_profile => prof, :partial => true }
-- 
1.7.10.1


[PATCH core 01/51] Core: Added sinatra-rabbit gem to gemspec

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/deltacloud-core.gemspec |    1 +
 1 file changed, 1 insertion(+)

diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
index 55aa182..54d88cc 100644
--- a/server/deltacloud-core.gemspec
+++ b/server/deltacloud-core.gemspec
@@ -68,6 +68,7 @@ Gem::Specification.new do |s|
   s.add_dependency('rake', '>= 0.8.7')
   s.add_dependency('haml', '>= 2.2.17')
   s.add_dependency('sinatra', '>= 0.9.4')
+  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
   s.add_dependency('rack', '>= 1.0.0')
   s.add_dependency('rack-accept')
   s.add_dependency('json', '>= 1.1.9')
-- 
1.7.10.1


Re: [PATCH core 14/51] Core: Added possiblity to list all Rabbit defined routes by rake rabbit:routes

Posted by David Lutterkort <lu...@redhat.com>.
On Mon, 2012-05-21 at 12:06 +0200, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/Rakefile |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
> 
> diff --git a/server/Rakefile b/server/Rakefile
> index 147cdcf..5d205ce 100644
> --- a/server/Rakefile
> +++ b/server/Rakefile
> @@ -193,3 +193,54 @@ namespace :mock do
>  
>    end
>  end
> +
> +namespace :openshift do
> +
> +  desc "Deploy Deltacloud API to OpenShift"
> +  task :deploy do
> +    print "RHN or OpenShift login with OpenShift Express access: "
> +    STDOUT.flush
> +    login = STDIN.gets.chomp
> +    print "Password: "
> +    system "stty -echo"
> +    password = STDIN.gets.chomp
> +    system "stty echo"
> +    puts `rhc-create-app --rhlogin #{login} --app deltacloudtest --password '#{password}' --type ruby-1.8`
> +  end
> +end

Oooh .. nice

David



[PATCH core 14/51] Core: Added possiblity to list all Rabbit defined routes by rake rabbit:routes

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Rakefile |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/server/Rakefile b/server/Rakefile
index 147cdcf..5d205ce 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -193,3 +193,54 @@ namespace :mock do
 
   end
 end
+
+namespace :openshift do
+
+  desc "Deploy Deltacloud API to OpenShift"
+  task :deploy do
+    print "RHN or OpenShift login with OpenShift Express access: "
+    STDOUT.flush
+    login = STDIN.gets.chomp
+    print "Password: "
+    system "stty -echo"
+    password = STDIN.gets.chomp
+    system "stty echo"
+    puts `rhc-create-app --rhlogin #{login} --app deltacloudtest --password '#{password}' --type ruby-1.8`
+  end
+end
+
+namespace :rabbit do
+  load File.join(File.dirname(__FILE__), 'config.ru')
+
+  desc "List the routes defined by Rabbit"
+  task :routes do
+    Deltacloud.collections.each do |c|
+      puts "\033[1;32;m#{c.name}\33[0m"
+      c.operations.each do |o|
+        puts "\033[1;37m%6s\033[0m :%-10s %-30s (%s)" % [
+          o.http_method.to_s.upcase,
+          o.operation_name,
+          o.full_path,
+          o.description[0..100]
+        ]
+      end
+      unless c.collections.empty?
+        puts
+        c.collections.each do |s|
+          puts "\033[1;32;m#{s.name}\33[0m"
+          s.operations.each do |o|
+            puts "\033[1;37m%6s\033[0m :%-10s %-30s (%s)" % [
+              o.http_method.to_s.upcase,
+              o.operation_name,
+              o.full_path,
+              o.description[0..100]
+            ]
+          end
+        end
+      end
+      puts
+    end
+  end
+
+end
+
-- 
1.7.10.1


[PATCH core 15/51] Core: Added the Deltacloud library wrapper (require 'lib/deltacloud')

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>

This will make possible to use Deltacloud drivers API with thirty-party
application whithout spawning a server.

Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud.rb         |   79 +++++++++++++++++++++++++++++++++-----
 server/tests/api/common.rb       |    1 +
 server/tests/api/driver_test.rb  |   79 ++++++++++++++++++++++++++++++++++++++
 server/tests/api/library_test.rb |   48 +++++++++++++++++++++++
 4 files changed, 197 insertions(+), 10 deletions(-)
 create mode 100644 server/tests/api/common.rb
 create mode 100644 server/tests/api/driver_test.rb
 create mode 100644 server/tests/api/library_test.rb

diff --git a/server/lib/deltacloud.rb b/server/lib/deltacloud.rb
index 6ff547e..6508d8d 100644
--- a/server/lib/deltacloud.rb
+++ b/server/lib/deltacloud.rb
@@ -1,4 +1,3 @@
-#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.  The
@@ -14,14 +13,74 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/drivers'
+require 'rubygems'
+
+load File.join(File.dirname(__FILE__), 'deltacloud/core_ext.rb')
+
+require 'ostruct'
+
+require_relative 'deltacloud/core_ext/string'
+require_relative 'deltacloud/core_ext/array'
+require_relative 'deltacloud/core_ext/hash'
+require_relative 'deltacloud/core_ext/integer'
+require_relative 'deltacloud/core_ext/proc'
+require_relative 'deltacloud/models'
+require_relative 'deltacloud/drivers'
+require_relative 'deltacloud/helpers/driver_helper'
+
+module Deltacloud
+
+  API_VERSION = '0.5.0'
+
+  def self.drivers
+    Drivers.driver_config
+  end
+
+  class Library
+    include Helpers::Drivers
+
+    attr_reader :backend, :credentials
+
+    def initialize(driver_name, opts={}, &block)
+      Thread.current[:driver] = driver_name.to_s
+      Thread.current[:provider] = opts[:provider]
+      @backend = driver
+      opts[:user] ||= 'mockuser'
+      opts[:password] ||= 'mockpassword'
+      @credentials = OpenStruct.new(:user => opts[:user], :password => opts[:password])
+      yield backend if block_given?
+    end
+
+    def version
+      Deltacloud::API_VERSION
+    end
+
+    def current_provider
+      Thread.current[:provider]
+    end
+
+    def current_driver
+      Thread.current[:driver]
+    end
+
+    def providers
+      Deltacloud.drivers[current_driver.to_sym]
+    end
+
+    def method_missing(name, *args)
+      return super unless backend.respond_to? name
+      begin
+        params = ([@credentials] + args).flatten
+        backend.send(name, *params)
+      rescue ArgumentError
+        backend.send(name, *args)
+      end
+    end
+
+  end
 
-require 'deltacloud/core_ext'
+  def self.new(driver_name, opts={}, &block)
+    Library.new(driver_name, opts, &block)
+  end
 
-require 'deltacloud/base_driver'
-require 'deltacloud/hardware_profile'
-require 'deltacloud/state_machine'
-require 'deltacloud/helpers'
-require 'deltacloud/models'
-require 'deltacloud/validation'
-require 'deltacloud/runner'
+end
diff --git a/server/tests/api/common.rb b/server/tests/api/common.rb
new file mode 100644
index 0000000..3554a81
--- /dev/null
+++ b/server/tests/api/common.rb
@@ -0,0 +1 @@
+require 'minitest/autorun'
diff --git a/server/tests/api/driver_test.rb b/server/tests/api/driver_test.rb
new file mode 100644
index 0000000..20f9197
--- /dev/null
+++ b/server/tests/api/driver_test.rb
@@ -0,0 +1,79 @@
+require_relative './common'
+require_relative '../../lib/deltacloud'
+
+begin
+  require 'arguments'
+rescue LoadError
+  puts "You don't have 'rdp-arguments' gems installed. (gem install rdp-arguments)"
+  exit(1)
+end
+require 'pp'
+
+describe 'Deltacloud drivers API' do
+
+  before do
+    @stderr = $stderr.clone
+    $stderr = StringIO.new
+  end
+
+  after do
+    $stderr = @stderr
+  end
+
+  it 'should pass the known method to Deltacloud driver' do
+    Deltacloud.new(:mock).hardware_profiles.must_be_kind_of Array
+    Deltacloud.new(:mock).hardware_profiles.wont_be_empty
+  end
+
+  it 'should raise NoMethodError when driver does not respond to method' do
+    lambda { Deltacloud.new(:mock).non_existing_method }.must_raise NoMethodError
+  end
+
+  it 'should apply the credentials to methods that require them' do
+    Deltacloud.new(:mock).realms.must_be_kind_of Array
+    Deltacloud.new(:mock).realms.wont_be_empty
+  end
+
+  it 'should allow to use different drivers' do
+    Deltacloud.new(:ec2).backend.must_be_instance_of Deltacloud::Drivers::Ec2::Ec2Driver
+    Deltacloud.new(:mock).backend.must_be_instance_of Deltacloud::Drivers::Mock::MockDriver
+  end
+
+  it 'should support loading all supported drivers' do
+    Deltacloud.drivers.keys.each do |key|
+      Deltacloud.new(key).current_driver.must_equal key.to_s
+    end
+  end
+
+  METHODS = {
+    :firewalls => [[:credentials], [:opts, "{  }"]],
+    :firewall  => [[:credentials], [:opts, "{  }"]],
+    :keys    => [[:credentials], [:opts, "{  }"]],
+    :key     => [[:credentials], [:opts]],
+    :storage_snapshots => [[:credentials], [:opts, "{  }"]],
+    :storage_snapshot  => [[:credentials], [:opts]],
+    :storage_volumes => [[:credentials], [:opts, "{  }"]],
+    :storage_volume  => [[:credentials], [:opts]],
+    :realms    => [[:credentials], [:opts, "{  }"]],
+    :realm     => [[:credentials], [:opts]],
+    :images    => [[:credentials], [:opts, "{  }"]],
+    :image     => [[:credentials], [:opts]],
+    :instances => [[:credentials], [:opts, "{  }"]],
+    :instance  => [[:credentials], [:opts]],
+    :create_instance => [[:credentials], [:image_id], [:opts, "{  }"]],
+    :destroy_instance => [[:credentials], [:id]],
+    :stop_instance => [[:credentials], [:id]],
+    :start_instance => [[:credentials], [:id]],
+    :reboot_instance => [[:credentials], [:id]],
+  }
+
+  Deltacloud.drivers.keys.each do |key|
+    METHODS.each do |m, definition|
+      it "should have the correct parameters for the :#{m} method in #{key} driver" do
+        next unless Deltacloud.new(key).backend.respond_to? m
+        Arguments.names(Deltacloud.new(key).backend.class, m).must_equal definition
+      end
+    end
+  end
+
+end
diff --git a/server/tests/api/library_test.rb b/server/tests/api/library_test.rb
new file mode 100644
index 0000000..72d00ef
--- /dev/null
+++ b/server/tests/api/library_test.rb
@@ -0,0 +1,48 @@
+require_relative './common'
+require_relative '../../lib/deltacloud'
+
+require 'pp'
+
+describe 'Deltacloud API Library' do
+
+  it 'should return the driver configuration' do
+    Deltacloud.must_respond_to :drivers
+    Deltacloud.drivers.wont_be_nil
+    Deltacloud.drivers.must_be_kind_of Hash
+  end
+
+  it 'should be constructed just using the driver parameter' do
+    Deltacloud.new(:mock).must_be_instance_of Deltacloud::Library
+    Deltacloud.new(:mock).current_provider.must_be_nil
+    Deltacloud.new(:mock).current_driver.must_equal 'mock'
+    Deltacloud.new(:mock).backend.must_be_instance_of Deltacloud::Drivers::Mock::MockDriver
+    Deltacloud.new(:mock).credentials.user.must_equal 'mockuser'
+    Deltacloud.new(:mock).credentials.password.must_equal 'mockpassword'
+  end
+
+  it 'should allow to set credentials' do
+    Deltacloud.new(:mock, :user => 'testuser', :password => 'testpassword').credentials.user.must_equal 'testuser'
+    Deltacloud.new(:mock, :user => 'testuser', :password => 'testpassword').credentials.password.must_equal 'testpassword'
+  end
+
+  it 'should allow to set the provider' do
+    Deltacloud.new(:mock, :provider => 'someprovider').current_provider.must_equal 'someprovider'
+    Deltacloud.new(:mock).current_provider.must_be_nil
+  end
+
+  it 'should return pre-defined providers for the driver' do
+    Deltacloud.new(:ec2).providers[:entrypoints].must_be_kind_of Hash
+  end
+
+  it 'should yield the backend driver' do
+    Deltacloud.new :mock do |mock|
+      mock.must_be_instance_of Deltacloud::Drivers::Mock::MockDriver
+    end
+  end
+
+  it 'should return the API version' do
+    Deltacloud::API_VERSION.wont_be_empty
+    Deltacloud::new(:mock).version.wont_be_empty
+  end
+
+end
-- 
1.7.10.1


[PATCH core 09/51] Core: Updated entrypoint views to list collections from Deltacloud module

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/views/api/show.html.haml |    7 +++----
 server/views/api/show.xml.haml  |   13 ++++++-------
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/server/views/api/show.html.haml b/server/views/api/show.html.haml
index 9a40860..4630a87 100644
--- a/server/views/api/show.html.haml
+++ b/server/views/api/show.html.haml
@@ -3,20 +3,19 @@
 
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview, :'data-inset' => 'true'}
-
     - Deltacloud.collections.each do |c|
       - next unless c.operation(:index).has_capability?
       %li
         %a{ :href => api_url_for(c.collection_name),  :'data-icon' => "arrow-r"}=c.collection_name.to_s.gsub('_', ' ').titlecase
 
-- if @providers.size > 1
+- unless driver.configured_providers.empty?
   %div{ :'data-role' => :footer, :'data-theme' => 'a'}
     %form{ :action => settings.root_url, :method => :post, :'data-ajax' => 'false'}
       - if @driver_name
-        %input{ :name => :driver, :type => :hidden, :value => @driver_name }/
+        %input{ :name => :driver, :type => :hidden, :value => driver.name }/
       %fieldset{ :'data-type' => "horizontal", :'data-role' => "controlgroup", :id => "providers" }
         %select{:name => 'provider', :'data-inline' => 'true', :'data-native-menu' => 'false'}
           %option{ :value => 'default'} default
-          - @providers.each do |provider|
+          - driver.configured_providers.each do |provider|
             %option{ :value => provider } #{provider}
         %button{ :type => :submit, :'data-inline' => "true"} Change Provider
diff --git a/server/views/api/show.xml.haml b/server/views/api/show.xml.haml
index 2b9f653..ad2df09 100644
--- a/server/views/api/show.xml.haml
+++ b/server/views/api/show.xml.haml
@@ -1,7 +1,6 @@
-%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])
-        %feature{ :name=>feature.name }
-          - for name,value in feature.constraints
-            %constraint{ :name=>name, :value=>value }
+%api{ :version => settings.version, :driver => driver_symbol, :provider => Thread.current[:provider] || ENV['API_PROVIDER'] }
+  - Deltacloud.collections.each do |c|
+    - next unless c.operation(:index).has_capability?
+    %link{ :rel => c.collection_name, :href => self.send(:"#{c.collection_name}_url")}
+      - c.features.select { |f| driver.class.has_feature?(c.collection_name, f.name) }.each do |f|
+        %feature{ :name => f.name }
-- 
1.7.10.1


[PATCH core 24/51] SBC: Renamed the driver class to match with common pattern

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers/sbc/sbc_client.rb |    2 +-
 server/lib/deltacloud/drivers/sbc/sbc_driver.rb |    6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/server/lib/deltacloud/drivers/sbc/sbc_client.rb b/server/lib/deltacloud/drivers/sbc/sbc_client.rb
index a0e36cb..97e89ca 100644
--- a/server/lib/deltacloud/drivers/sbc/sbc_client.rb
+++ b/server/lib/deltacloud/drivers/sbc/sbc_client.rb
@@ -21,7 +21,7 @@ require 'digest/md5'
 
 module Deltacloud
   module Drivers
-    module SBC
+    module Sbc
 
 class FixtureNotFound < Exception; end
 
diff --git a/server/lib/deltacloud/drivers/sbc/sbc_driver.rb b/server/lib/deltacloud/drivers/sbc/sbc_driver.rb
index c7b109e..2e09a15 100644
--- a/server/lib/deltacloud/drivers/sbc/sbc_driver.rb
+++ b/server/lib/deltacloud/drivers/sbc/sbc_driver.rb
@@ -15,17 +15,17 @@
 # under the License.
 
 require 'nokogiri'
-require 'deltacloud/drivers/sbc/sbc_client'
+require_relative './sbc_client'
 
 module Deltacloud
   module Drivers
-    module SBC
+    module Sbc
 #
 # Driver for the IBM Smart Business Cloud (SBC).
 #
 # 31 January 2011
 #
-class SBCDriver < Deltacloud::BaseDriver
+class SbcDriver < Deltacloud::BaseDriver
   #
   # Retrieves images
   #
-- 
1.7.10.1


Re: Deltacloud revamp using Sinatra::Base (rev 3 - final? ;-)

Posted by David Lutterkort <lu...@redhat.com>.
On Mon, 2012-05-21 at 12:06 +0200, mfojtik@redhat.com wrote:
> Sorry for the 'super-big-patch' once again, but this should be the final stable
> version with all nits and tests fixed so far.

Gets an ACK from me; great stuff.

David



[PATCH core 44/51] Core: Advertise the hardware_profiles only if driver support them.

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/hardware_profiles.rb        |    6 ++++--
 server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb |    2 ++
 server/lib/deltacloud/drivers/openstack/openstack_driver.rb   |    2 ++
 server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb   |    6 ++++--
 server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb       |    2 ++
 server/lib/deltacloud/helpers/rabbit_helper.rb                |    8 ++++----
 6 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/server/lib/deltacloud/collections/hardware_profiles.rb b/server/lib/deltacloud/collections/hardware_profiles.rb
index ff01d4a..5c72aff 100644
--- a/server/lib/deltacloud/collections/hardware_profiles.rb
+++ b/server/lib/deltacloud/collections/hardware_profiles.rb
@@ -16,10 +16,12 @@
 module Deltacloud::Collections
   class HardwareProfiles < Base
 
+    check_capability :for => lambda { |m| !driver.class.send(m).empty? }
+
     collection :hardware_profiles do
 
-      standard_index_operation
-      standard_show_operation
+      standard_index_operation :capability => :hardware_profiles
+      standard_show_operation :capability => :hardware_profiles
 
     end
 
diff --git a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
index 2c6203b..cc1f13e 100644
--- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
+++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
@@ -27,6 +27,8 @@ module Deltacloud
 
 class OpennebulaDriver < Deltacloud::BaseDriver
 
+  define_hardware_profile('default')
+
   ######################################################################
   # Hardware profiles
   #####################################################################
diff --git a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
index 12dadef..0ed2baf 100644
--- a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
+++ b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
@@ -36,6 +36,8 @@ module Deltacloud
           stopped.to( :finish )         .automatically
         end
 
+        define_hardware_profile('default')
+
         def hardware_profiles(credentials, opts = {})
           os = new_client(credentials)
           results = []
diff --git a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
index c8030ad..ca1c236 100644
--- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
+++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
@@ -29,6 +29,8 @@ class RackspaceDriver < Deltacloud::BaseDriver
   feature :instances, :user_files
   feature :images, :user_name
 
+  define_hardware_profile('default')
+
   def hardware_profiles(credentials, opts = {})
     rs = new_client( credentials )
     results = []
@@ -189,8 +191,8 @@ class RackspaceDriver < Deltacloud::BaseDriver
     start.to( :pending )          .on( :create )
     pending.to( :running )        .automatically
     running.to( :running )        .on( :reboot )
-    running.to( :shutting_down )  .on( :stop )
-    shutting_down.to( :stopped )  .automatically
+    running.to( :stopping )  .on( :stop )
+    stopping.to( :stopped )  .automatically
     stopped.to( :finish )         .automatically
   end
 
diff --git a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
index a6a1e58..6d30cd4 100644
--- a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
+++ b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
@@ -33,6 +33,8 @@ module Deltacloud::Drivers::Vsphere
     feature :instances, :user_data
     feature :instances, :user_name
 
+    define_hardware_profile('default')
+
     # There is just one hardware profile where memory is measured using maximum
     # memory available on ESX for virtual machines and CPU using maximum free
     # CPU cores in ESX.
diff --git a/server/lib/deltacloud/helpers/rabbit_helper.rb b/server/lib/deltacloud/helpers/rabbit_helper.rb
index 252abe2..d6a472a 100644
--- a/server/lib/deltacloud/helpers/rabbit_helper.rb
+++ b/server/lib/deltacloud/helpers/rabbit_helper.rb
@@ -16,16 +16,16 @@
 
 Sinatra::Rabbit::Collection.class_eval do
 
-  def self.standard_index_operation
+  def self.standard_index_operation(opts={})
     collection_name = @collection_name
-    operation :index, :with_capability => collection_name do
+    operation :index, :with_capability => opts[:capability] || collection_name do
       control { filter_all collection_name }
     end
   end
 
-  def self.standard_show_operation
+  def self.standard_show_operation(opts={})
     collection_name = @collection_name
-    operation :show, :with_capability => collection_name do
+    operation :show, :with_capability => opts[:capability] || collection_name do
       control { show collection_name.to_s.singularize.intern }
     end
   end
-- 
1.7.10.1


[PATCH core 12/51] CIMI: Moved code from CIMI server.rb and split it to smaller collections like in Deltacloud

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/collections.rb                     |   58 ++
 server/lib/cimi/collections/address_templates.rb   |   49 +
 server/lib/cimi/collections/addresses.rb           |   74 ++
 server/lib/cimi/collections/cloud_entry_point.rb   |   32 +
 server/lib/cimi/collections/entity_metadata.rb     |   48 +
 server/lib/cimi/collections/machine_admins.rb      |   74 ++
 .../lib/cimi/collections/machine_configurations.rb |   49 +
 server/lib/cimi/collections/machine_images.rb      |   50 +
 server/lib/cimi/collections/machines.rb            |  157 ++++
 .../lib/cimi/collections/network_configurations.rb |   47 +
 server/lib/cimi/collections/network_templates.rb   |   48 +
 server/lib/cimi/collections/networks.rb            |  125 +++
 .../cimi/collections/routing_group_templates.rb    |   47 +
 server/lib/cimi/collections/routing_groups.rb      |   48 +
 .../lib/cimi/collections/volume_configurations.rb  |   48 +
 server/lib/cimi/collections/volume_images.rb       |   50 +
 server/lib/cimi/collections/volumes.rb             |   80 ++
 server/lib/cimi/collections/vsp_configurations.rb  |   48 +
 server/lib/cimi/collections/vsp_templates.rb       |   50 +
 server/lib/cimi/collections/vsps.rb                |  108 +++
 server/lib/cimi/helpers.rb                         |  104 +++
 server/lib/cimi/model.rb                           |   67 --
 server/lib/cimi/model/action.rb                    |   24 -
 server/lib/cimi/model/address.rb                   |   72 --
 server/lib/cimi/model/address_collection.rb        |   34 -
 server/lib/cimi/model/address_template.rb          |   54 --
 .../lib/cimi/model/address_template_collection.rb  |   34 -
 server/lib/cimi/model/base.rb                      |  249 -----
 server/lib/cimi/model/cloud_entry_point.rb         |   48 -
 server/lib/cimi/model/entity_metadata.rb           |   83 --
 .../lib/cimi/model/entity_metadata_collection.rb   |   31 -
 server/lib/cimi/model/errors.rb                    |   48 -
 server/lib/cimi/model/machine.rb                   |  229 -----
 server/lib/cimi/model/machine_admin.rb             |   59 --
 server/lib/cimi/model/machine_admin_collection.rb  |   34 -
 server/lib/cimi/model/machine_collection.rb        |   34 -
 server/lib/cimi/model/machine_configuration.rb     |   70 --
 .../cimi/model/machine_configuration_collection.rb |   34 -
 server/lib/cimi/model/machine_image.rb             |   46 -
 server/lib/cimi/model/machine_image_collection.rb  |   34 -
 server/lib/cimi/model/machine_template.rb          |   41 -
 .../lib/cimi/model/machine_template_collection.rb  |   34 -
 server/lib/cimi/model/network.rb                   |  106 ---
 server/lib/cimi/model/network_collection.rb        |   34 -
 server/lib/cimi/model/network_configuration.rb     |   49 -
 .../cimi/model/network_configuration_collection.rb |   34 -
 server/lib/cimi/model/network_template.rb          |   36 -
 .../lib/cimi/model/network_template_collection.rb  |   35 -
 server/lib/cimi/model/routing_group.rb             |   34 -
 server/lib/cimi/model/routing_group_collection.rb  |   34 -
 server/lib/cimi/model/routing_group_template.rb    |   34 -
 .../model/routing_group_template_collection.rb     |   35 -
 server/lib/cimi/model/schema.rb                    |  277 ------
 server/lib/cimi/model/volume.rb                    |  103 ---
 server/lib/cimi/model/volume_collection.rb         |   34 -
 server/lib/cimi/model/volume_configuration.rb      |   60 --
 .../cimi/model/volume_configuration_collection.rb  |   34 -
 server/lib/cimi/model/volume_image.rb              |   49 -
 server/lib/cimi/model/volume_image_collection.rb   |   34 -
 server/lib/cimi/model/volume_template.rb           |   23 -
 .../lib/cimi/model/volume_template_collection.rb   |   34 -
 server/lib/cimi/model/vsp.rb                       |  102 ---
 server/lib/cimi/model/vsp_collection.rb            |   34 -
 server/lib/cimi/model/vsp_configuration.rb         |   40 -
 .../lib/cimi/model/vsp_configuration_collection.rb |   34 -
 server/lib/cimi/model/vsp_template.rb              |   34 -
 server/lib/cimi/model/vsp_template_collection.rb   |   34 -
 server/lib/cimi/models.rb                          |   75 ++
 server/lib/cimi/models/action.rb                   |   24 +
 server/lib/cimi/models/address.rb                  |   72 ++
 server/lib/cimi/models/address_collection.rb       |   34 +
 server/lib/cimi/models/address_template.rb         |   54 ++
 .../lib/cimi/models/address_template_collection.rb |   34 +
 server/lib/cimi/models/base.rb                     |  249 +++++
 server/lib/cimi/models/cloud_entry_point.rb        |   46 +
 server/lib/cimi/models/entity_metadata.rb          |   84 ++
 .../lib/cimi/models/entity_metadata_collection.rb  |   31 +
 server/lib/cimi/models/errors.rb                   |   48 +
 server/lib/cimi/models/machine.rb                  |  227 +++++
 server/lib/cimi/models/machine_admin.rb            |   59 ++
 server/lib/cimi/models/machine_admin_collection.rb |   34 +
 server/lib/cimi/models/machine_collection.rb       |   34 +
 server/lib/cimi/models/machine_configuration.rb    |   70 ++
 .../models/machine_configuration_collection.rb     |   34 +
 server/lib/cimi/models/machine_image.rb            |   46 +
 server/lib/cimi/models/machine_image_collection.rb |   34 +
 server/lib/cimi/models/machine_template.rb         |   41 +
 .../lib/cimi/models/machine_template_collection.rb |   34 +
 server/lib/cimi/models/network.rb                  |  109 +++
 server/lib/cimi/models/network_collection.rb       |   34 +
 server/lib/cimi/models/network_configuration.rb    |   49 +
 .../models/network_configuration_collection.rb     |   34 +
 server/lib/cimi/models/network_template.rb         |   36 +
 .../lib/cimi/models/network_template_collection.rb |   35 +
 server/lib/cimi/models/routing_group.rb            |   34 +
 server/lib/cimi/models/routing_group_collection.rb |   34 +
 server/lib/cimi/models/routing_group_template.rb   |   34 +
 .../models/routing_group_template_collection.rb    |   35 +
 server/lib/cimi/models/schema.rb                   |  277 ++++++
 server/lib/cimi/models/volume.rb                   |  103 +++
 server/lib/cimi/models/volume_collection.rb        |   34 +
 server/lib/cimi/models/volume_configuration.rb     |   60 ++
 .../cimi/models/volume_configuration_collection.rb |   34 +
 server/lib/cimi/models/volume_image.rb             |   49 +
 server/lib/cimi/models/volume_image_collection.rb  |   34 +
 server/lib/cimi/models/volume_template.rb          |   23 +
 .../lib/cimi/models/volume_template_collection.rb  |   34 +
 server/lib/cimi/models/vsp.rb                      |  102 +++
 server/lib/cimi/models/vsp_collection.rb           |   34 +
 server/lib/cimi/models/vsp_configuration.rb        |   40 +
 .../cimi/models/vsp_configuration_collection.rb    |   34 +
 server/lib/cimi/models/vsp_template.rb             |   34 +
 server/lib/cimi/models/vsp_template_collection.rb  |   34 +
 server/lib/cimi/server.rb                          |  959 +-------------------
 114 files changed, 4148 insertions(+), 3645 deletions(-)
 create mode 100644 server/lib/cimi/collections.rb
 create mode 100644 server/lib/cimi/collections/address_templates.rb
 create mode 100644 server/lib/cimi/collections/addresses.rb
 create mode 100644 server/lib/cimi/collections/cloud_entry_point.rb
 create mode 100644 server/lib/cimi/collections/entity_metadata.rb
 create mode 100644 server/lib/cimi/collections/machine_admins.rb
 create mode 100644 server/lib/cimi/collections/machine_configurations.rb
 create mode 100644 server/lib/cimi/collections/machine_images.rb
 create mode 100644 server/lib/cimi/collections/machines.rb
 create mode 100644 server/lib/cimi/collections/network_configurations.rb
 create mode 100644 server/lib/cimi/collections/network_templates.rb
 create mode 100644 server/lib/cimi/collections/networks.rb
 create mode 100644 server/lib/cimi/collections/routing_group_templates.rb
 create mode 100644 server/lib/cimi/collections/routing_groups.rb
 create mode 100644 server/lib/cimi/collections/volume_configurations.rb
 create mode 100644 server/lib/cimi/collections/volume_images.rb
 create mode 100644 server/lib/cimi/collections/volumes.rb
 create mode 100644 server/lib/cimi/collections/vsp_configurations.rb
 create mode 100644 server/lib/cimi/collections/vsp_templates.rb
 create mode 100644 server/lib/cimi/collections/vsps.rb
 create mode 100644 server/lib/cimi/helpers.rb
 delete mode 100644 server/lib/cimi/model.rb
 delete mode 100644 server/lib/cimi/model/action.rb
 delete mode 100644 server/lib/cimi/model/address.rb
 delete mode 100644 server/lib/cimi/model/address_collection.rb
 delete mode 100644 server/lib/cimi/model/address_template.rb
 delete mode 100644 server/lib/cimi/model/address_template_collection.rb
 delete mode 100644 server/lib/cimi/model/base.rb
 delete mode 100644 server/lib/cimi/model/cloud_entry_point.rb
 delete mode 100644 server/lib/cimi/model/entity_metadata.rb
 delete mode 100644 server/lib/cimi/model/entity_metadata_collection.rb
 delete mode 100644 server/lib/cimi/model/errors.rb
 delete mode 100644 server/lib/cimi/model/machine.rb
 delete mode 100644 server/lib/cimi/model/machine_admin.rb
 delete mode 100644 server/lib/cimi/model/machine_admin_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_configuration.rb
 delete mode 100644 server/lib/cimi/model/machine_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_image.rb
 delete mode 100644 server/lib/cimi/model/machine_image_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_template.rb
 delete mode 100644 server/lib/cimi/model/machine_template_collection.rb
 delete mode 100644 server/lib/cimi/model/network.rb
 delete mode 100644 server/lib/cimi/model/network_collection.rb
 delete mode 100644 server/lib/cimi/model/network_configuration.rb
 delete mode 100644 server/lib/cimi/model/network_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/network_template.rb
 delete mode 100644 server/lib/cimi/model/network_template_collection.rb
 delete mode 100644 server/lib/cimi/model/routing_group.rb
 delete mode 100644 server/lib/cimi/model/routing_group_collection.rb
 delete mode 100644 server/lib/cimi/model/routing_group_template.rb
 delete mode 100644 server/lib/cimi/model/routing_group_template_collection.rb
 delete mode 100644 server/lib/cimi/model/schema.rb
 delete mode 100644 server/lib/cimi/model/volume.rb
 delete mode 100644 server/lib/cimi/model/volume_collection.rb
 delete mode 100644 server/lib/cimi/model/volume_configuration.rb
 delete mode 100644 server/lib/cimi/model/volume_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/volume_image.rb
 delete mode 100644 server/lib/cimi/model/volume_image_collection.rb
 delete mode 100644 server/lib/cimi/model/volume_template.rb
 delete mode 100644 server/lib/cimi/model/volume_template_collection.rb
 delete mode 100644 server/lib/cimi/model/vsp.rb
 delete mode 100644 server/lib/cimi/model/vsp_collection.rb
 delete mode 100644 server/lib/cimi/model/vsp_configuration.rb
 delete mode 100644 server/lib/cimi/model/vsp_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/vsp_template.rb
 delete mode 100644 server/lib/cimi/model/vsp_template_collection.rb
 create mode 100644 server/lib/cimi/models.rb
 create mode 100644 server/lib/cimi/models/action.rb
 create mode 100644 server/lib/cimi/models/address.rb
 create mode 100644 server/lib/cimi/models/address_collection.rb
 create mode 100644 server/lib/cimi/models/address_template.rb
 create mode 100644 server/lib/cimi/models/address_template_collection.rb
 create mode 100644 server/lib/cimi/models/base.rb
 create mode 100644 server/lib/cimi/models/cloud_entry_point.rb
 create mode 100644 server/lib/cimi/models/entity_metadata.rb
 create mode 100644 server/lib/cimi/models/entity_metadata_collection.rb
 create mode 100644 server/lib/cimi/models/errors.rb
 create mode 100644 server/lib/cimi/models/machine.rb
 create mode 100644 server/lib/cimi/models/machine_admin.rb
 create mode 100644 server/lib/cimi/models/machine_admin_collection.rb
 create mode 100644 server/lib/cimi/models/machine_collection.rb
 create mode 100644 server/lib/cimi/models/machine_configuration.rb
 create mode 100644 server/lib/cimi/models/machine_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/machine_image.rb
 create mode 100644 server/lib/cimi/models/machine_image_collection.rb
 create mode 100644 server/lib/cimi/models/machine_template.rb
 create mode 100644 server/lib/cimi/models/machine_template_collection.rb
 create mode 100644 server/lib/cimi/models/network.rb
 create mode 100644 server/lib/cimi/models/network_collection.rb
 create mode 100644 server/lib/cimi/models/network_configuration.rb
 create mode 100644 server/lib/cimi/models/network_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/network_template.rb
 create mode 100644 server/lib/cimi/models/network_template_collection.rb
 create mode 100644 server/lib/cimi/models/routing_group.rb
 create mode 100644 server/lib/cimi/models/routing_group_collection.rb
 create mode 100644 server/lib/cimi/models/routing_group_template.rb
 create mode 100644 server/lib/cimi/models/routing_group_template_collection.rb
 create mode 100644 server/lib/cimi/models/schema.rb
 create mode 100644 server/lib/cimi/models/volume.rb
 create mode 100644 server/lib/cimi/models/volume_collection.rb
 create mode 100644 server/lib/cimi/models/volume_configuration.rb
 create mode 100644 server/lib/cimi/models/volume_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/volume_image.rb
 create mode 100644 server/lib/cimi/models/volume_image_collection.rb
 create mode 100644 server/lib/cimi/models/volume_template.rb
 create mode 100644 server/lib/cimi/models/volume_template_collection.rb
 create mode 100644 server/lib/cimi/models/vsp.rb
 create mode 100644 server/lib/cimi/models/vsp_collection.rb
 create mode 100644 server/lib/cimi/models/vsp_configuration.rb
 create mode 100644 server/lib/cimi/models/vsp_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/vsp_template.rb
 create mode 100644 server/lib/cimi/models/vsp_template_collection.rb

diff --git a/server/lib/cimi/collections.rb b/server/lib/cimi/collections.rb
new file mode 100644
index 0000000..b675fc4
--- /dev/null
+++ b/server/lib/cimi/collections.rb
@@ -0,0 +1,58 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI
+
+  def self.collection_names
+    @collections.map { |c| c.collection_name }
+  end
+
+  def self.collections
+    @collections ||= []
+  end
+
+  module Collections
+
+    def self.collection(name)
+      CIMI.collections.find { |c| c.collection_name == name }
+    end
+
+    def self.cimi_modules
+      @cimi_modules ||= []
+    end
+
+    Dir[File.join(File::dirname(__FILE__), "collections", "*.rb")].each do |collection|
+      require collection
+      base_collection_name = File.basename(collection).gsub('.rb', '')
+      cimi_module_class = CIMI::Collections.const_get(base_collection_name.camelize)
+      cimi_modules << cimi_module_class
+      unless cimi_module_class.collections.nil?
+        cimi_module_class.collections.each do |c|
+          CIMI.collections << c
+        end
+      else
+        warn "WARNING: File %s placed in collections directory but does not have any collections defined" % base_collection_name
+      end
+    end
+
+    def self.included(klass)
+      klass.class_eval do
+        CIMI::Collections.cimi_modules.each { |c| use c }
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/address_templates.rb b/server/lib/cimi/collections/address_templates.rb
new file mode 100644
index 0000000..db59507
--- /dev/null
+++ b/server/lib/cimi/collections/address_templates.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class AddressTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :address_templates do
+
+      operation :index do
+        description 'List all AddressTemplates in the AddressTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          address_templates = AddressTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {address_templates.to_xml}
+            format.json {address_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific AddressTemplate'
+        control do
+          address_template = CIMI::Model::AddressTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {address_template.to_xml}
+            format.json {address_template.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/addresses.rb b/server/lib/cimi/collections/addresses.rb
new file mode 100644
index 0000000..96871c1
--- /dev/null
+++ b/server/lib/cimi/collections/addresses.rb
@@ -0,0 +1,74 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Addresses < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :addresses do
+
+      description 'An Address represents an IP address, and its associated metdata, for a particular Network.'
+
+      operation :index do
+        description 'List all Addresses in the AddressCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          addresses = AddressCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {addresses.to_xml}
+            format.json {addresses.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific Address'
+        control do
+          address = CIMI::Model::Address.find(params[:id], self)
+          respond_to do |format|
+            format.xml {address.to_xml}
+            format.json {address.to_json}
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Address"
+        control do
+          if request.content_type.end_with?("json")
+            address = CIMI::Model::Address.create(request.body.read, self, :json)
+          else
+            address = CIMI::Model::Address.create(request.body.read, self, :xml)
+          end
+          respond_to do |format|
+            format.xml { address.to_xml }
+            format.json { address.to_json }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified Address"
+        param :id, :string, :required
+        control do
+          CIMI::Model::Address.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/cloud_entry_point.rb b/server/lib/cimi/collections/cloud_entry_point.rb
new file mode 100644
index 0000000..79454f3
--- /dev/null
+++ b/server/lib/cimi/collections/cloud_entry_point.rb
@@ -0,0 +1,32 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class CloudEntryPoint < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection  :cloudEntryPoint do
+      description 'Cloud entry point'
+      operation :index do
+        description "list all resources of the cloud"
+        control do
+          redirect API_ROOT_URL
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/entity_metadata.rb b/server/lib/cimi/collections/entity_metadata.rb
new file mode 100644
index 0000000..84e1fec
--- /dev/null
+++ b/server/lib/cimi/collections/entity_metadata.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class EntityMetadata < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :entity_metadata do
+
+      operation :index do
+        description "List all entity metadata defined for this provider"
+        control do
+          entity_metadata = CIMI::Model::EntityMetadataCollection.default(self)
+          respond_to do |format|
+            format.xml{entity_metadata.to_xml}
+            format.json{entity_metadata.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description "Get the entity metadata for a specific collection"
+        control do
+          entity_metadata = EntityMetadata.find(params[:id], self)
+          respond_to do |format|
+            format.xml{entity_metadata.to_xml}
+            format.json{entity_metadata.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machine_admins.rb b/server/lib/cimi/collections/machine_admins.rb
new file mode 100644
index 0000000..c413cc9
--- /dev/null
+++ b/server/lib/cimi/collections/machine_admins.rb
@@ -0,0 +1,74 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class MachineAdmins < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machine_admins do
+      description 'Machine Admin entity'
+
+      operation :index do
+        description "List all machine admins"
+        param :CIMISelect,  :string,  :optional
+        control do
+          machine_admins = MachineAdminCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machine_admins.to_xml }
+            format.json { machine_admins.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific machine admin"
+        control do
+          machine_admin = MachineAdmin.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine_admin.to_xml }
+            format.json { machine_admin.to_json }
+          end
+        end
+      end
+
+      operation :create do
+        description "Show specific machine admin"
+        control do
+          if request.content_type.end_with?("+json")
+            new_admin = MachineAdmin.create_from_json(request.body.read, self)
+          else
+            new_admin = MachineAdmin.create_from_xml(request.body.read, self)
+          end
+          status 201 # Created
+          respond_to do |format|
+            format.json { new_admin.to_json }
+            format.xml { new_admin.to_xml }
+          end
+        end
+      end
+
+      operation :delete do
+        description "Delete specified MachineAdmin entity"
+        control do
+          MachineAdmin.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machine_configurations.rb b/server/lib/cimi/collections/machine_configurations.rb
new file mode 100644
index 0000000..5b09e6a
--- /dev/null
+++ b/server/lib/cimi/collections/machine_configurations.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class MachineConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machine_configurations do
+      description 'List all machine configurations'
+
+      operation :index do
+        param :CIMISelect,  :string,  :optional
+        description "List all machine configurations"
+        control do
+          machine_configs = MachineConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machine_configs.to_xml }
+            format.json { machine_configs.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        control do
+          machine_conf = MachineConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine_conf.to_xml }
+            format.json { machine_conf.to_json }
+          end
+        end
+
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machine_images.rb b/server/lib/cimi/collections/machine_images.rb
new file mode 100644
index 0000000..1296279
--- /dev/null
+++ b/server/lib/cimi/collections/machine_images.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class MachineImages < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machine_images do
+      description 'List all machine images'
+
+      operation :index do
+        description "List all machine configurations"
+        param :CIMISelect,  :string,  :optional
+        control do
+          machine_images = MachineImageCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machine_images.to_xml }
+            format.json { machine_images.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific machine image."
+        control do
+          machine_image = MachineImage.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine_image.to_xml }
+            format.json { machine_image.to_json }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machines.rb b/server/lib/cimi/collections/machines.rb
new file mode 100644
index 0000000..0abf63a
--- /dev/null
+++ b/server/lib/cimi/collections/machines.rb
@@ -0,0 +1,157 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Machines < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machines do
+      description 'List all machine'
+
+      operation :index do
+        param :CIMISelect,  :string,  :optional
+        description "List all machines"
+        control do
+          machines = MachineCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machines.to_xml }
+            format.json { machines.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine.to_xml }
+            format.json { machine.to_json }
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Machine entity."
+        control do
+          if request.content_type.end_with?("+json")
+            new_machine = Machine.create_from_json(request.body.read, self)
+          else
+            new_machine = Machine.create_from_xml(request.body.read, self)
+          end
+          status 201 # Created
+          respond_to do |format|
+            format.json { new_machine.to_json }
+            format.xml { new_machine.to_xml }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified machine."
+        param :id,          :string,    :required
+        control do
+          Machine.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :stop do
+        description "Stop specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          if request.content_type.end_with?("+json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          machine.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      operation :restart do
+        description "Start specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          if request.content_type.end_with?("+json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          machine.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      operation :start do
+        description "Start specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          if request.content_type.end_with?("+json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          machine.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      #NOTE: The routes for attach/detach used here are NOT as specified by CIMI
+      #will likely move later. CIMI specifies PUT of the whole Machine description
+      #with inclusion/ommission of the volumes you want [att|det]ached
+      action :attach_volume, :http_method => :put do
+        description "Attach CIMI Volume(s) to a machine."
+        control do
+          if request.content_type.end_with?("+json")
+            volumes_to_attach = Volume.find_to_attach_from_json(request.body.read, self)
+          else
+            volumes_to_attach = Volume.find_to_attach_from_xml(request.body.read, self)
+          end
+          machine = Machine.attach_volumes(volumes_to_attach, self)
+          respond_to do |format|
+            format.json{ machine.to_json}
+            format.xml{machine.to_xml}
+          end
+        end
+      end
+
+      action :detach_volume, :http_method => :put do
+        description "Detach CIMI Volume(s) from a machine."
+        control do
+          if request.content_type.end_with?("+json")
+            volumes_to_detach = Volume.find_to_attach_from_json(request.body.read, self)
+          else
+            volumes_to_detach = Volume.find_to_attach_from_xml(request.body.read, self)
+          end
+          machine = Machine.detach_volumes(volumes_to_detach, self)
+          respond_to do |format|
+            format.json{ machine.to_json}
+            format.xml{machine.to_xml}
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/network_configurations.rb b/server/lib/cimi/collections/network_configurations.rb
new file mode 100644
index 0000000..02452a8
--- /dev/null
+++ b/server/lib/cimi/collections/network_configurations.rb
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class NetworkConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :network_configurations do
+
+      operation :index do
+        description 'List all NetworkConfigurations'
+        param :CIMISelect, :string, :optional
+        control do
+          network_configurations = NetworkConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { network_configurations.to_xml  }
+            format.json { network_configurations.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific NetworkConfiguration'
+        control do
+          network_config = NetworkConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml { network_config.to_xml }
+            format.json { network_config.to_json }
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/network_templates.rb b/server/lib/cimi/collections/network_templates.rb
new file mode 100644
index 0000000..0ff82b2
--- /dev/null
+++ b/server/lib/cimi/collections/network_templates.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class NetworkTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :network_templates do
+
+      operation :index do
+        description 'List all Network Templates in the NetworkTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          network_templates = NetworkTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {network_templates.to_xml}
+            format.json {network_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific Network Template'
+        control do
+          network_template = NetworkTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {network_template.to_xml}
+            format.json {network_template.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/networks.rb b/server/lib/cimi/collections/networks.rb
new file mode 100644
index 0000000..0aa21e8
--- /dev/null
+++ b/server/lib/cimi/collections/networks.rb
@@ -0,0 +1,125 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Networks < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :networks do
+      description 'A Network represents an abstraction of a layer 2 broadcast domain'
+
+      operation :index do
+        description "List all Networks"
+        param :CIMISelect,  :string,  :optional
+        control do
+          networks = NetworkCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { networks.to_xml }
+            format.json { networks.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show a specific Network"
+        control do
+          network = Network.find(params[:id], self)
+          respond_to do |format|
+            format.xml { network.to_xml }
+            format.json { network.to_json }
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Network"
+        control do
+          if request.content_type.end_with?("json")
+            network = Network.create(request.body.read, self, :json)
+          else
+            network = Network.create(request.body.read, self, :xml)
+          end
+          respond_to do |format|
+            format.xml { network.to_xml}
+            format.json { network.to_json }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified Network"
+        param :id, :string, :required
+        control do
+          Network.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :start do
+        description "Start specific network."
+        control do
+          network = Network.find(params[:id], self)
+          report_error(404) unless network
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          network.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :stop do
+        description "Stop specific network."
+        control do
+          network = Network.find(params[:id], self)
+          report_error(404) unless network
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          network.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :suspend do
+        description "Suspend specific network."
+        control do
+          network = Network.find(params[:id], self)
+          report_error(404) unless network
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          network.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/routing_group_templates.rb b/server/lib/cimi/collections/routing_group_templates.rb
new file mode 100644
index 0000000..995b1f8
--- /dev/null
+++ b/server/lib/cimi/collections/routing_group_templates.rb
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class RoutingGroupTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :routing_group_templates do
+
+      operation :index do
+        description 'List all RoutingGroupTemplates in the RoutingGroupTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          routing_group_templates = RoutingGroupTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {routing_group_templates.to_xml}
+            format.json {routing_group_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific RoutingGroupTemplate'
+        control do
+          routing_group_template = RoutingGroupTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {routing_group_template.to_xml}
+            format.json {routing_group_template.to_json}
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/routing_groups.rb b/server/lib/cimi/collections/routing_groups.rb
new file mode 100644
index 0000000..5e7ccc5
--- /dev/null
+++ b/server/lib/cimi/collections/routing_groups.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class RoutingGroups < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :routing_groups do
+
+      operation :index do
+        description 'List all RoutingGroups in the RoutingGroupsCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          routing_groups = RoutingGroupCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {routing_groups.to_xml}
+            format.json {routing_groups.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific RoutingGroup'
+        control do
+          routing_group = RoutingGroup.find(params[:id], self)
+          respond_to do |format|
+            format.xml {routing_group.to_xml}
+            format.json {routing_group.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/volume_configurations.rb b/server/lib/cimi/collections/volume_configurations.rb
new file mode 100644
index 0000000..055e28c
--- /dev/null
+++ b/server/lib/cimi/collections/volume_configurations.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VolumeConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :volume_configurations do
+
+      operation :index do
+        description "Get list all VolumeConfigurations"
+        param :CIMISelect,  :string,  :optional
+        control do
+          volume_configuration = VolumeConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { volume_configuration.to_xml }
+            format.json { volume_configuration.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Get a specific VolumeConfiguration"
+        control do
+          volume_config = VolumeConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml { volume_config.to_xml }
+            format.json { volume_config.json }
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/volume_images.rb b/server/lib/cimi/collections/volume_images.rb
new file mode 100644
index 0000000..78432b1
--- /dev/null
+++ b/server/lib/cimi/collections/volume_images.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VolumeImages < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :volume_images do
+      description 'This entity represents an image that could be place on a pre-loaded volume.'
+
+      operation :index do
+        description "List all volumes images"
+        param :CIMISelect,  :string,  :optional
+        control do
+          volume_images = VolumeImageCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { volume_images.to_xml }
+            format.json { volume_images.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show a specific volume image"
+        control do
+          volume_image = VolumeImage.find(params[:id], self)
+          respond_to do |format|
+            format.xml { volume_image.to_xml }
+            format.json { volume_image.to_json }
+          end
+        end
+      end
+    end
+
+
+  end
+end
diff --git a/server/lib/cimi/collections/volumes.rb b/server/lib/cimi/collections/volumes.rb
new file mode 100644
index 0000000..1c45c9e
--- /dev/null
+++ b/server/lib/cimi/collections/volumes.rb
@@ -0,0 +1,80 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Volumes < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :volumes do
+
+      operation :index do
+        description "List all volumes"
+        param :CIMISelect,  :string,  :optional
+        control do
+          volumes = VolumeCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { volumes.to_xml }
+            format.json { volumes.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific Volume."
+        control do
+          volume = Volume.find(params[:id], self)
+          if volume
+            respond_to do |format|
+              format.xml  { volume.to_xml  }
+              format.json { volume.to_json }
+            end
+          else
+            report_error(404)
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Volume."
+        control do
+          content_type = (request.content_type.end_with?("+json") ? :json  : :xml)
+          #((request.content_type.end_with?("+xml")) ? :xml : report_error(415) ) FIXME
+          case content_type
+          when :json
+            new_volume = Volume.create_from_json(request.body.read, self)
+          when :xml
+            new_volume = Volume.create_from_xml(request.body.read, self)
+          end
+          respond_to do |format|
+            format.json { new_volume.to_json }
+            format.xml { new_volume.to_xml }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified Volume"
+        param :id, :string, :required
+        control do
+          Volume.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+
+  end
+end
diff --git a/server/lib/cimi/collections/vsp_configurations.rb b/server/lib/cimi/collections/vsp_configurations.rb
new file mode 100644
index 0000000..31acceb
--- /dev/null
+++ b/server/lib/cimi/collections/vsp_configurations.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VspConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :vsp_configurations do
+
+      operation :index do
+        description 'List all VSPConfigurations in the VSPConfigurationCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          vsp_configs = VSPConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {vsp_configs.to_xml}
+            format.json {vsp_configs.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific VSPConfiguration'
+        control do
+          vsp_config = VSPConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml {vsp_config.to_xml}
+            format.json {vsp_config.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/vsp_templates.rb b/server/lib/cimi/collections/vsp_templates.rb
new file mode 100644
index 0000000..503de50
--- /dev/null
+++ b/server/lib/cimi/collections/vsp_templates.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VspTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :vsp_templates do
+
+      description 'The VSP Template is a set of Configuration values for realizing a VSP. A VSP Template may be used to create multiple VSPs'
+
+      operation :index do
+        description 'List all VSPTemplates in the VSPTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          vsp_templates = VSPTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {vsp_templates.to_xml}
+            format.json {vsp_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific VSPTemplate'
+        control do
+          vsp_template = VSPTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {vsp_template.to_xml}
+            format.json {vsp_template.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/vsps.rb b/server/lib/cimi/collections/vsps.rb
new file mode 100644
index 0000000..52b1a5a
--- /dev/null
+++ b/server/lib/cimi/collections/vsps.rb
@@ -0,0 +1,108 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Vsps < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :vsps do
+
+      description 'A VSP represents the connection parameters of a network port'
+
+      operation :index do
+        description 'List all VSPs in the VSPCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          vsps = VSPCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {vsps.to_xml}
+            format.json {vsps.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific VSP'
+        control do
+          vsp = VSP.find(params[:id], self)
+          respond_to do |format|
+            format.xml {vsp.to_xml}
+            format.json {vsp.to_json}
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new VSP"
+        control do
+          if request.content_type.end_with?("json")
+            vsp = CIMI::Model::VSP.create(request.body.read, self, :json)
+          else
+            vsp = CIMI::Model::VSP.create(request.body.read, self, :xml)
+          end
+          respond_to do |format|
+            format.xml { vsp.to_xml }
+            format.json { vsp.to_json }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified VSP"
+        control do
+          CIMI::Model::VSP.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :start do
+        description "Start specific VSP."
+        param :id,          :string,    :required
+        control do
+          vsp = VSP.find(params[:id], self)
+          report_error(404) unless vsp
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          vsp.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :stop do
+        description "Stop specific VSP."
+        control do
+          vsp = VSP.find(params[:id], self)
+          report_error(404) unless vsp
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          vsp.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/helpers.rb b/server/lib/cimi/helpers.rb
new file mode 100644
index 0000000..4535c39
--- /dev/null
+++ b/server/lib/cimi/helpers.rb
@@ -0,0 +1,104 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud; end
+module CIMI; end
+
+require_relative '../deltacloud/drivers'
+require_relative '../deltacloud/models'
+require_relative '../deltacloud/helpers/driver_helper'
+require_relative '../deltacloud/helpers/auth_helper'
+require_relative '../deltacloud/helpers/url_helper'
+require_relative '../deltacloud/helpers/assets_helper'
+require_relative '../deltacloud/helpers/deltacloud_helper'
+require_relative '../deltacloud/helpers/rabbit_helper'
+require_relative '../deltacloud/helpers/rabbit_helper'
+require_relative '../deltacloud/core_ext/string'
+require_relative '../deltacloud/core_ext/array'
+require_relative '../deltacloud/core_ext/hash'
+require_relative '../deltacloud/core_ext/integer'
+require_relative '../deltacloud/core_ext/proc'
+require_relative './helpers/cimi_helper'
+require_relative './models'
+
+module CIMI::Collections
+  class Base < Sinatra::Base
+
+    extend Deltacloud::Helpers::Drivers
+    include Sinatra::Rabbit::Features
+    include CIMI::Model
+
+    helpers Deltacloud::Helpers::Drivers
+    helpers Sinatra::AuthHelper
+    helpers Sinatra::UrlForHelper
+    helpers Sinatra::StaticAssets::Helpers
+    helpers Rack::RespondTo::Helpers
+    helpers Deltacloud::Helpers::Application
+
+    register Rack::RespondTo
+
+    enable :xhtml
+    enable :dump_errors
+    enable :show_errors
+    disable :show_exceptions
+
+    set :root_url, API_ROOT_URL
+    set :version, API_VERSION
+    set :root, File.join(File.dirname(__FILE__), '..', '..')
+    set :views, root + '/views/cimi'
+    set :public_folder, root + '/public'
+
+    error do
+      report_error
+    end
+
+    error Deltacloud::ExceptionHandler::ValidationFailure do
+      report_error
+    end
+
+    before do
+      # Respond with 400, If we don't get a http Host header,
+      halt 400, "Unable to find HTTP Host header" if @env['HTTP_HOST'] == nil
+    end
+
+    after do
+      headers 'X-CIMI-Specification-Version' => API_VERSION
+    end
+
+    def self.new_route_for(route, &block)
+      get route_for('/' + route.to_s + '/new') do
+        instance_eval(&block) if block_given?
+        respond_to do |format|
+          format.html do
+            haml :"#{route}/new"
+          end
+        end
+      end
+    end
+
+    def self.check_capability(opts={})
+      Sinatra::Rabbit.set :check_capability, opts[:for]
+    end
+
+    def self.check_features(opts={})
+      Sinatra::Rabbit.set :check_features, opts[:for]
+    end
+
+    def self.route_for(url)
+      "#{settings.root_url}#{url}"
+    end
+
+  end
+end
diff --git a/server/lib/cimi/model.rb b/server/lib/cimi/model.rb
deleted file mode 100644
index fa3c771..0000000
--- a/server/lib/cimi/model.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-# Declare namespace for CIMI model
-#
-module CIMI
-  module Model; end
-end
-
-require 'cimi/model/schema'
-require 'cimi/model/base'
-require 'cimi/model/errors'
-require 'cimi/model/cloud_entry_point'
-require 'cimi/model/machine_template'
-require 'cimi/model/machine_image'
-require 'cimi/model/machine_configuration'
-require 'cimi/model/action'
-require 'cimi/model/machine'
-require 'cimi/model/volume'
-require 'cimi/model/machine_admin'
-require 'cimi/model/volume_configuration'
-require 'cimi/model/volume_image'
-require 'cimi/model/volume_template'
-require 'cimi/model/machine_template_collection'
-require 'cimi/model/machine_image_collection'
-require 'cimi/model/machine_configuration_collection'
-require 'cimi/model/machine_collection'
-require 'cimi/model/volume_collection'
-require 'cimi/model/machine_admin_collection'
-require 'cimi/model/volume_configuration_collection'
-require 'cimi/model/volume_image_collection'
-require 'cimi/model/volume_template_collection'
-require 'cimi/model/entity_metadata'
-require 'cimi/model/entity_metadata_collection'
-require 'cimi/model/network'
-require 'cimi/model/network_collection'
-require 'cimi/model/network_configuration'
-require 'cimi/model/network_configuration_collection'
-require 'cimi/model/network_template'
-require 'cimi/model/network_template_collection'
-require 'cimi/model/routing_group'
-require 'cimi/model/routing_group_collection'
-require 'cimi/model/routing_group_template'
-require 'cimi/model/routing_group_template_collection'
-require 'cimi/model/vsp'
-require 'cimi/model/vsp_collection'
-require 'cimi/model/vsp_configuration'
-require 'cimi/model/vsp_configuration_collection'
-require 'cimi/model/vsp_template'
-require 'cimi/model/vsp_template_collection'
-require 'cimi/model/address'
-require 'cimi/model/address_collection'
-require 'cimi/model/address_template'
-require 'cimi/model/address_template_collection'
diff --git a/server/lib/cimi/model/action.rb b/server/lib/cimi/model/action.rb
deleted file mode 100644
index c1c9908..0000000
--- a/server/lib/cimi/model/action.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Action < CIMI::Model::Base
-
-  text :action
-
-  def name
-    action.split('/').last.strip.intern
-  end
-
-end
diff --git a/server/lib/cimi/model/address.rb b/server/lib/cimi/model/address.rb
deleted file mode 100644
index 8838331..0000000
--- a/server/lib/cimi/model/address.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Address < CIMI::Model::Base
-
-  text :ip
-
-  text :hostname
-
-  text :allocation
-
-  text :default_gateway
-
-  text :dns
-
-  text :mac_address
-
-  text :protocol
-
-  text :mask
-
-  href :network
-
-  href :resource
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.addresses(context.credentials, {:env=>context})
-    else
-      context.driver.addresses(context.credentials, {:id=>id, :env=>context})
-    end
-  end
-
-  def self.create(request_body, context, type)
-    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
-    if input["addressTemplate"]["href"] #by reference
-      address_template = AddressTemplate.find(context.href_id(input["addressTemplate"]["href"], :address_templates), context)
-    else
-      case type
-        when :json
-          address_template = AddressTemplate.from_json(JSON.generate(input["addressTemplate"]))
-        when :xml
-          xml = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
-          address_template = AddressTemplate.from_xml(XmlSimple.xml_out(xml["addressTemplate"][0]))
-      end
-    end
-    params = {:name=>input["name"], :description=>input["description"], :address_template=>address_template, :env=>context }
-    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
-    context.driver.create_address(context.credentials, params)
-  end
-
-  def self.delete!(id, context)
-    context.driver.delete_address(context.credentials, id)
-  end
-
-end
diff --git a/server/lib/cimi/model/address_collection.rb b/server/lib/cimi/model/address_collection.rb
deleted file mode 100644
index eef6c51..0000000
--- a/server/lib/cimi/model/address_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::AddressCollection < CIMI::Model::Base
-
-  act_as_root_entity :address
-
-  array :addresses do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.addresses_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} AddressCollection",
-      :addresses => CIMI::Model::Address.all(context).map { |addr| { :href => addr.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/address_template.rb b/server/lib/cimi/model/address_template.rb
deleted file mode 100644
index 9d2c409..0000000
--- a/server/lib/cimi/model/address_template.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::AddressTemplate < CIMI::Model::Base
-
-  text :ip
-
-  text :hostname
-
-  text :allocation
-
-  text :default_gateway
-
-  text :dns
-
-  text :mac_address
-
-  text :protocol
-
-  text :mask
-
-  href :network
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.address_templates(context.credentials, {:env=>context})
-    else
-      context.driver.address_templates(context.credentials, {:id=>id, :env=>context})
-    end
-  end
-
-  def self.create(request_body, context, type)
-  end
-
-  def self.delete!(id, context)
-  end
-
-end
diff --git a/server/lib/cimi/model/address_template_collection.rb b/server/lib/cimi/model/address_template_collection.rb
deleted file mode 100644
index e973252..0000000
--- a/server/lib/cimi/model/address_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::AddressTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :address_template
-
-  array :address_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.address_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} AddressTemplateCollection",
-      :address_templates => AddressTemplate.all(context).map { |addr| { :href => addr.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/base.rb b/server/lib/cimi/model/base.rb
deleted file mode 100644
index 16812ac..0000000
--- a/server/lib/cimi/model/base.rb
+++ /dev/null
@@ -1,249 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'xmlsimple'
-require 'json'
-
-# The base class for any CIMI object that we either read from a request or
-# write as a response. This class handles serializing/deserializing XML and
-# JSON into a common form.
-#
-# == Defining the schema
-#
-# The conversion of XML and JSON into internal objects is based on a schema
-# that is defined through a DSL:
-#
-#   class Machine < CIMI::Model::Base
-#     text :status
-#     href :meter
-#     array :volumes do
-#       scalar :href, :attachment_point, :protocol
-#     end
-#   end
-#
-# The DSL automatically takes care of converting identifiers from their
-# underscored form to the camel-cased form used by CIMI. The above class
-# can be used in the following way:
-#
-#   machine = Machine.from_xml(some_xml)
-#   if machine.status == "UP"
-#     ...
-#   end
-#   sda = machine.volumes.find { |v| v.attachment_point == "/dev/sda" }
-#   handle_meter(machine.meter.href)
-#
-# The keywords for the DSL are
-#   [scalar(names, ...)]
-#     Define a scalar attribute; in JSON, this is represented as a string
-#     property. In XML, this can be represented in a number of ways,
-#     depending on whether the option :text is set:
-#       * :text not set: attribute on the enclosing element
-#       * :text == :direct: the text content of the enclosing element
-#       * :text == :nested: the text content of an element +<name>...</name>+
-#   [text(names)]
-#     A shorthand for +scalar(names, :text => :nested)+, i.e., for
-#     attributes that in XML are represented by their own tags
-#   [href(name)]
-#     A shorthand for +struct name { scalar :href }+; in JSON, this is
-#     represented as +{ name: { "href": string } }+, and in XML as +<name
-#     href="..."/>+
-#   [struct(name, opts, &block)]
-#     A structured subobject; the block defines the schema of the
-#     subobject. The +:content+ option can be used to specify the attribute
-#     that should receive the content of hte corresponding XML element
-#   [array(name, opts, &block)]
-#     An array of structured subobjects; the block defines the schema of
-#     the subobjects.
-
-module CIMI::Model
-
-  def self.register_as_root_entity!(name)
-    @root_entities ||= []
-    @root_entities << name
-    unless CIMI::Model::CloudEntryPoint.href_defined?(name)
-      CIMI::Model::CloudEntryPoint.send(:href, name.underscore)
-    end
-  end
-
-  def self.root_entities
-    @root_entities || []
-  end
-
-end
-
-class CIMI::Model::Base
-
-  #
-  # We keep the values of the attributes in a hash
-  #
-  attr_reader :attribute_values
-
-  # Keep the list of all attributes in an array +attributes+; for each
-  # attribute, we also define a getter and a setter to access/change the
-  # value for that attribute
-  class << self
-    def base_schema
-      @schema ||= CIMI::Model::Schema.new
-    end
-
-    def clone_base_schema
-      @schema_duped = true
-      @schema = Marshal::load(Marshal.dump(superclass.base_schema))
-    end
-
-    def base_schema_cloned?
-      @schema_duped
-    end
-
-    private :'clone_base_schema', :'base_schema_cloned?'
-
-    def inherited(child)
-      child.instance_eval do
-        def schema
-          base_schema_cloned? ? @schema : clone_base_schema
-        end
-      end
-    end
-
-    def add_attributes!(names, attr_klass, &block)
-      if self.respond_to? :schema
-        schema.add_attributes!(names, attr_klass, &block)
-      else
-        base_schema.add_attributes!(names, attr_klass, &block)
-      end
-      names.each do |name|
-        define_method(name) { @attribute_values[name] }
-        define_method(:"#{name}=") { |newval| @attribute_values[name] = newval }
-      end
-    end
-
-    # Return Array of links to current CIMI object
-    def all_uri(context)
-      self.all(context).map { |e| { :href => e.id } }
-    end
-  end
-
-  extend CIMI::Model::Schema::DSL
-
-  def [](a)
-    @attribute_values[a]
-  end
-
-  def []=(a, v)
-    @attribute_values[a] = v
-  end
-
-  #
-  # Factory methods
-  #
-  def initialize(values = {})
-    @attribute_values = values
-  end
-
-  # Construct a new object from the XML representation +xml+
-  def self.from_xml(text)
-    xml = XmlSimple.xml_in(text, :force_content => true)
-    model = self.new
-    @schema.from_xml(xml, model)
-    model
-  end
-
-  # Construct a new object
-  def self.from_json(text)
-    json = JSON::parse(text)
-    model = self.new
-    @schema.from_json(json, model)
-    model
-  end
-
-  #
-  # Serialize
-  #
-
-  def self.xml_tag_name
-    self.name.split("::").last
-  end
-
-  def self.to_json(model)
-    JSON::unparse(@schema.to_json(model))
-  end
-
-  def self.to_xml(model)
-    xml = @schema.to_xml(model)
-    xml["xmlns"] = "http://www.dmtf.org/cimi"
-    XmlSimple.xml_out(xml, :root_name => xml_tag_name)
-  end
-
-  def to_json
-    self.class.to_json(self)
-  end
-
-  def to_xml
-    self.class.to_xml(self)
-  end
-
-  #
-  # Common attributes for all resources
-  #
-  text :id, :name, :description, :created
-
-  # FIXME: this doesn't match with JSON
-  hash :property, :content => :value do
-    scalar :name
-  end
-
-  def self.act_as_root_entity(name=nil)
-    if name
-      name = name.to_s.camelize.pluralize
-    else
-      name = xml_tag_name.pluralize.uncapitalize
-    end
-    CIMI::Model.register_as_root_entity! name
-  end
-
-  def self.all(_self); find(:all, _self); end
-
-  def filter_by(filter_opts)
-    return self if filter_opts.nil?
-    return filter_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
-    case filter_opts
-      when /^([\w\_]+)$/ then filter_attributes([$1.intern])
-      when /^([\w\_]+)\[(\d+\-\d+)\]$/ then filter_by_arr_range($1.intern, $2)
-      when /^([\w\_]+)\[(\d+)\]$/ then filter_by_arr_index($1.intern, $2)
-      else self
-    end
-  end
-
-  private
-
-  def filter_attributes(attr_list)
-    attrs = attr_list.inject({}) do |result, attr|
-      result[attr] = self.send(attr) if self.respond_to?(attr)
-      result
-    end
-    self.class.new(attrs)
-  end
-
-  def filter_by_arr_index(attr, filter)
-    return self unless self.respond_to?(attr)
-    self.class.new(attr => [self.send(attr)[filter.to_i]])
-  end
-
-  def filter_by_arr_range(attr, filter)
-    return self unless self.respond_to?(attr)
-    filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
-    self.class.new(attr => self.send(attr)[filter])
-  end
-end
diff --git a/server/lib/cimi/model/cloud_entry_point.rb b/server/lib/cimi/model/cloud_entry_point.rb
deleted file mode 100644
index 5db94df..0000000
--- a/server/lib/cimi/model/cloud_entry_point.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
-
-  array :entity_metadata do
-    scalar :href
-  end
-
-  def self.create(context)
-    self.new(entities(context).merge({
-      :name => context.driver.name,
-      :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
-      :id => context.cloudEntryPoint_url,
-      :created => Time.now,
-      :entity_metadata => EntityMetadata.all_uri(context)
-    }))
-  end
-
-  # Return an Hash of the CIMI root entities used in CloudEntryPoint
-  def self.entities(context)
-    CIMI::Model.root_entities.inject({}) do |result, entity|
-      if context.respond_to? :"#{entity.underscore}_url"
-        result[entity.underscore] = { :href => context.send(:"#{entity.underscore}_url") }
-      end
-      result
-    end
-  end
-
-  private
-
-  def self.href_defined?(entity)
-    true if schema.attribute_names.include? entity.underscore
-  end
-
-end
diff --git a/server/lib/cimi/model/entity_metadata.rb b/server/lib/cimi/model/entity_metadata.rb
deleted file mode 100644
index bc20ff3..0000000
--- a/server/lib/cimi/model/entity_metadata.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-class CIMI::Model::EntityMetadata < CIMI::Model::Base
-
-text :type_uri
-
-  array :attributes do
-    scalar :name
-    scalar :namespace
-    scalar :type
-    scalar :required
-    scalar :constraints
-  end
-
-  array :operations do
-    scalar :name
-    scalar :uri
-    scalar :description
-    scalar :method
-    scalar :input_message
-    scalar :output_message
-  end
-
-  def self.find(id, context)
-    entity_metadata = []
-    if id == :all
-      CIMI::Model.root_entities.each do |entity|
-        entity_class = CIMI::Model.const_get("#{entity.singularize}")
-        entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?(:create_entity_metadata)
-      end
-      return entity_metadata
-    else
-      entity_class = CIMI::Model.const_get("#{id.camelize}")
-      if entity_class.respond_to?(:create_entity_metadata)
-        entity_class.create_entity_metadata(context)
-      end
-    end
-  end
-
-  def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
-    deltacloud_features = context.driver.features(dcloud_entity)
-    metadata_attributes = deltacloud_features.map{|f| attributes_from_feature(f)}
-    from_feature(cimi_entity, context, metadata_attributes.flatten!)
-  end
-
-  def includes_attribute?(attribute)
-    self.attributes.any?{|attr| attr[:name] == attribute}
-  end
-
-  private
-
-  def self.attributes_from_feature(feature)
-    feature.operations.first.params.inject([]) do |result, param|
-      result << {
-        :name=>(feature.name == :user_name ? :name : param[0]),
-        :type=> "xs:string",
-        :required=> (param[1] and param[1].optional?) ? "false" : "true",
-        :constraints=> (feature.constraints.empty? ? (feature.description.nil? ? "" : feature.description): feature.constraints)
-      }
-    end
-  end
-
-  def self.from_feature(cimi_entity, context, metadata_attributes)
-    self.new(:name => cimi_entity, :uri=>"#{context.entity_metadata_url}/#{cimi_entity.underscore}",
-             :type_uri=> context.send("#{cimi_entity.pluralize.underscore}_url"),
-             :attributes => metadata_attributes)
-  end
-
-end
diff --git a/server/lib/cimi/model/entity_metadata_collection.rb b/server/lib/cimi/model/entity_metadata_collection.rb
deleted file mode 100644
index 63db7f7..0000000
--- a/server/lib/cimi/model/entity_metadata_collection.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::EntityMetadataCollection < CIMI::Model::Base
-
-  array :entity_metadata do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.entity_metadata_url,
-      :name => 'default',
-      :created => Time.now,
-      :entity_metadata => EntityMetadata.all_uri(context)
-   )
-  end
-
-end
diff --git a/server/lib/cimi/model/errors.rb b/server/lib/cimi/model/errors.rb
deleted file mode 100644
index 7c090ed..0000000
--- a/server/lib/cimi/model/errors.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module CIMI::Model
-
-  class NotFound < StandardError
-    attr_accessor :code
-
-    def initialize
-      super("Requested Entity Not Found")
-      self.code = 404
-    end
-
-  end
-
-  class BadRequest < StandardError
-    attr_accessor :code
-    def initialize(msg="")
-      super(msg)
-      self.code=400
-    end
-  end
-
-  class NotImplemented < StandardError
-    attr_accessor :code
-
-    def initialize
-      super("Requested operation is not implemented by backend provider")
-      self.code = 501
-    end
-
-  end
-
-end
-
-
diff --git a/server/lib/cimi/model/machine.rb b/server/lib/cimi/model/machine.rb
deleted file mode 100644
index 939629a..0000000
--- a/server/lib/cimi/model/machine.rb
+++ /dev/null
@@ -1,229 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/models/instance_address'
-
-class CIMI::Model::Machine < CIMI::Model::Base
-
-  text :state
-  text :cpu
-
-  struct :memory do
-    scalar :quantity
-    scalar :units
-  end
-
-  href :event_log
-
-  array :disks do
-    struct :capacity do
-      scalar :quantity
-      scalar :units
-    end
-    scalar :format
-    scalar :attachment_point
-  end
-
-  array :volumes do
-    scalar :href
-    scalar :protocol
-    scalar :attachment_point
-  end
-
-  array :network_interfaces do
-    href :vsp
-    text :hostname, :mac_address, :state, :protocol, :allocation
-    text :address, :default_gateway, :dns, :max_transmission_unit
-  end
-
-  array :meters do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    instances = []
-    if id == :all
-      instances = context.driver.instances(context.credentials)
-      instances.map { |instance| from_instance(instance, context) }.compact
-    else
-      instance = context.driver.instance(context.credentials, :id => id)
-      raise CIMI::Model::NotFound unless instance
-      from_instance(instance, context)
-    end
-  end
-
-  def self.create_from_json(body, context)
-    json = JSON.parse(body)
-    hardware_profile_id = xml['machineTemplate']['machineConfig']["href"].split('/').last
-    image_id = xml['machineTemplate']['machineImage']["href"].split('/').last
-    instance = context.create_instance(context.credentials, image_id, { :hwp_id => hardware_profile_id })
-    from_instance(instance, context)
-  end
-
-  def self.create_from_xml(body, context)
-    xml = XmlSimple.xml_in(body)
-    machine_template = xml['machineTemplate'][0]
-    hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
-    image_id = machine_template['machineImage'][0]["href"].split('/').last
-    additional_params = {}
-    additional_params[:name] =xml['name'][0] if xml['name']
-    if machine_template.has_key? 'machineAdmin'
-      additional_params[:keyname] = machine_template['machineAdmin'][0]["href"].split('/').last
-    end
-    instance = context.driver.create_instance(context.credentials, image_id, {
-      :hwp_id => hardware_profile_id
-    }.merge(additional_params))
-    from_instance(instance, context)
-  end
-
-  def perform(action, context, &block)
-    begin
-      if context.driver.send(:"#{action.name}_instance", context.credentials, self.name)
-        block.callback :success
-      else
-        raise "Operation failed to execute on given Machine"
-      end
-    rescue => e
-      block.callback :failure, e.message
-    end
-  end
-
-  def self.delete!(id, context)
-    context.driver.destroy_instance(context.credentials, id)
-  end
-
-  def self.create_entity_metadata(context)
-    cimi_entity = self.name.split("::").last
-    metadata = EntityMetadata.metadata_from_deltacloud_features(cimi_entity, :instances, context)
-    unless metadata.includes_attribute?(:name)
-      metadata.attributes << {:name=>"name", :required=>"false",
-                   :constraints=>"Determined by the cloud provider", :type=>"xs:string"}
-    end
-    metadata
-  end
-
-  def self.attach_volumes(volumes, context)
-    volumes.each do |vol|
-      context.driver.attach_storage_volume(context.credentials,
-      {:id=>vol[:volume].name, :instance_id=>context.params[:id], :device=>vol[:attachment_point]})
-    end
-    self.find(context.params[:id], context)
-  end
-
-  def self.detach_volumes(volumes, context)
-    volumes.each do |vol|
-      context.driver.detach_storage_volume(context.credentials, {:id=>vol[:volume].name, :instance_id => context.params[:id]})
-    end
-    self.find(context.params[:id], context)
-  end
-
-  private
-
-  def self.from_instance(instance, context)
-    cpu =  memory = disks = (instance.instance_profile.id == "opaque")? "n/a" : nil
-    self.new(
-      :name => instance.id,
-      :description => instance.name,
-      :created => instance.launch_time,
-      :id => context.machine_url(instance.id),
-      :state => convert_instance_state(instance.state),
-      :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
-      :memory => memory || convert_instance_memory(instance.instance_profile, context),
-      :disks => disks || convert_instance_storage(instance.instance_profile, context),
-      :network_interfaces => convert_instance_addresses(instance),
-      :operations => convert_instance_actions(instance, context),
-      :volumes=>convert_storage_volumes(instance, context),
-      :property => convert_instance_properties(instance, context)
-    )
-  end
-
-  # FIXME: This will convert 'RUNNING' state to 'STARTED'
-  # which is defined in CIMI (p65)
-  #
-  def self.convert_instance_state(state)
-    ('RUNNING' == state) ? 'STARTED' : state
-  end
-
-  def self.convert_instance_properties(instance, context)
-    properties = []
-    properties << { :name => :machine_image, :value => context.machine_image_url(instance.image_id) }
-    if instance.respond_to? :keyname
-      properties << { :name => :machine_admin, :value => context.machine_admin_url(instance.keyname) }
-    end
-    properties
-  end
-
-  def self.convert_instance_cpu(profile, context)
-    cpu_override = profile.overrides.find { |p, v| p == :cpu }
-    if cpu_override.nil?
-      MachineConfiguration.find(profile.id, context).cpu
-    else
-      cpu_override[1]
-    end
-  end
-
-  def self.convert_instance_memory(profile, context)
-    machine_conf = MachineConfiguration.find(profile.name, context)
-    memory_override = profile.overrides.find { |p, v| p == :memory }
-    {
-      :quantity => memory_override.nil? ? machine_conf.memory[:quantity] : memory_override[1],
-      :units => machine_conf.memory[:units]
-    }
-  end
-
-  def self.convert_instance_storage(profile, context)
-    machine_conf = MachineConfiguration.find(profile.name, context)
-    storage_override = profile.overrides.find { |p, v| p == :storage }
-    [
-      { :capacity => {
-          :quantity => storage_override.nil? ? machine_conf.disks.first[:capacity][:quantity] : storage_override[1],
-          :units => machine_conf.disks.first[:capacity][:units]
-        }
-      }
-    ]
-  end
-
-  def self.convert_instance_addresses(instance)
-    (instance.public_addresses + instance.private_addresses).collect do |address|
-      {
-        :hostname => address.is_hostname? ? address : nil,
-        :mac_address => address.is_mac? ? address : nil,
-        :state => 'Active',
-        :protocol => 'IPv4',
-        :address => address.is_ipv4? ? address : nil,
-        :allocation => 'Static'
-      }
-    end
-  end
-
-  def self.convert_instance_actions(instance, context)
-    instance.actions.collect do |action|
-      action = :destroy if action == :delete # In CIMI destroy operation become delete
-      action = :restart if action == :reboot  # In CIMI reboot operation become restart
-      { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://www.dmtf.org/cimi/action/#{action}" }
-    end
-  end
-
-  def self.convert_storage_volumes(instance, context)
-    instance.storage_volumes ||= [] #deal with nilpointers
-    instance.storage_volumes.map{|vol| {:href=>context.volume_url(vol.keys.first),
-                                       :attachment_point=>vol.values.first} }
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_admin.rb b/server/lib/cimi/model/machine_admin.rb
deleted file mode 100644
index fed7c80..0000000
--- a/server/lib/cimi/model/machine_admin.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineAdmin < CIMI::Model::Base
-
-  text :username
-  text :password
-  text :key
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id == :all
-      keys = context.driver.keys(context.credentials)
-      keys.map { |key| from_key(key, context) }
-    else
-      key = context.driver.key(context.credentials, :id => id)
-      from_key(key, context)
-    end
-  end
-
-  def self.create_from_xml(body, context)
-    machine_admin = MachineAdmin.from_xml(body)
-    key = context.driver.create_key(context.credentials, :key_name => machine_admin.name)
-    from_key(key, context)
-  end
-
-  def self.delete!(id, context)
-    context.driver.destroy_key(context.credentials, :id => id)
-  end
-
-  private
-
-  def self.from_key(key, context)
-    self.new(
-      :name => key.id,
-      :username => key.username,
-      :password => key.is_password? ? key.password : key.fingerprint,
-      :key => key.is_key? ? key.pem_rsa_key : nil,
-      :id => context.machine_admin_url(key.id),
-      :created => Time.now
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_admin_collection.rb b/server/lib/cimi/model/machine_admin_collection.rb
deleted file mode 100644
index fd76a52..0000000
--- a/server/lib/cimi/model/machine_admin_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineAdminCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_admin
-
-  array :machine_admins do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_admins_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineAdminCollection",
-      :machine_admins => MachineAdmin.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_collection.rb b/server/lib/cimi/model/machine_collection.rb
deleted file mode 100644
index 27aa61b..0000000
--- a/server/lib/cimi/model/machine_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine
-
-  array :machines do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machines_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineCollection",
-      :machines => Machine.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_configuration.rb b/server/lib/cimi/model/machine_configuration.rb
deleted file mode 100644
index f9d98f2..0000000
--- a/server/lib/cimi/model/machine_configuration.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineConfiguration < CIMI::Model::Base
-
-  struct :memory do
-    scalar :quantity
-    scalar :units
-  end
-
-  text :cpu
-
-  array :disks do
-    struct :capacity do
-      scalar :quantity
-      scalar :units
-    end
-    scalar :format
-    scalar :attachment_point
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    profiles = []
-    if id == :all
-      profiles = context.driver.hardware_profiles(context.credentials)
-      profiles.map { |profile| from_hardware_profile(profile, context) }.compact
-    else
-      profile = context.driver.hardware_profile(context.credentials, id)
-      from_hardware_profile(profile, context)
-    end
-  end
-
-  private
-
-  def self.from_hardware_profile(profile, context)
-    # We accept just profiles with all properties set
-    return unless profile.memory or profile.cpu or profile.storage
-    memory = profile.memory.value || profile.memory.default
-    cpu = profile.cpu.value || profile.cpu.default
-    storage = profile.storage.value || profile.storage.default
-    machine_hash = {
-      :name => profile.name,
-      :description => "Machine Configuration with #{memory} #{profile.memory.unit} "+
-        "of memory and #{cpu} CPU",
-      :cpu => cpu,
-      :created => Time.now.to_s,  # FIXME: DC hardware_profile has no mention about created_at
-      :memory => { :quantity => profile.memory.value || profile.memory.default, :units => profile.memory.unit },
-      :disks => [ { :capacity => { :quantity => profile.storage.value || profile.storage.default, :units => profile.storage.unit } } ],
-      :id => context.machine_configuration_url(profile.name)
-    }
-    self.new(machine_hash)
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_configuration_collection.rb b/server/lib/cimi/model/machine_configuration_collection.rb
deleted file mode 100644
index 171acac..0000000
--- a/server/lib/cimi/model/machine_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineConfigurationCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_configuration
-
-  array :machine_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineConfigurationCollection",
-      :machine_configurations => MachineConfiguration.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_image.rb b/server/lib/cimi/model/machine_image.rb
deleted file mode 100644
index 7389475..0000000
--- a/server/lib/cimi/model/machine_image.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineImage < CIMI::Model::Base
-
-  href :image_location
-  text :image_data
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    images = []
-    if id == :all
-      images = context.driver.images(context.credentials)
-      images.map { |image| from_image(image, context) }
-    else
-      image = context.driver.image(context.credentials, :id => id)
-      from_image(image, context)
-    end
-  end
-
-  def self.from_image(image, context)
-    self.new(
-      :name => image.id,
-      :id => context.machine_image_url(image.id),
-      :description => image.description,
-      :created => Time.now.to_s,
-      :image_location => { :href => "#{context.driver.name}://#{image.id}" } # FIXME
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_image_collection.rb b/server/lib/cimi/model/machine_image_collection.rb
deleted file mode 100644
index b02ede7..0000000
--- a/server/lib/cimi/model/machine_image_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineImageCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_image
-
-  array :machine_images do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_images_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineImageCollection",
-      :machine_images => MachineImage.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_template.rb b/server/lib/cimi/model/machine_template.rb
deleted file mode 100644
index 8a88052..0000000
--- a/server/lib/cimi/model/machine_template.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineTemplate < CIMI::Model::Base
-
-  href :machine_config
-  href :machine_image
-  href :machine_admin
-
-  array :volumes do
-    scalar :href
-    scalar :protocol
-    scalar :attachment_point
-  end
-
-  array :volume_templates do
-    scalar :href, :attachment_point, :protocol
-  end
-
-  array :network_interfaces do
-    href :vsp
-    text :hostname, :mac_address, :state, :protocol, :allocation
-    text :address, :default_gateway, :dns, :max_transmission_unit
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-end
diff --git a/server/lib/cimi/model/machine_template_collection.rb b/server/lib/cimi/model/machine_template_collection.rb
deleted file mode 100644
index e1e8d30..0000000
--- a/server/lib/cimi/model/machine_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_template
-
-  array :machine_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_template_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineTemplateCollection",
-      :machine_templates => MachineTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/network.rb b/server/lib/cimi/model/network.rb
deleted file mode 100644
index cbfbae0..0000000
--- a/server/lib/cimi/model/network.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Network < CIMI::Model::Base
-
-  text :state
-
-  text :access
-
-  text :bandwidth_limit
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  href :routing_group
-
-  href :event_log
-
-  array :meters do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    networks=[]
-    if id==:all
-      networks = context.driver.networks(context.credentials, {:env=>context})
-    else
-      networks = context.driver.networks(context.credentials, {:id=>id, :env=>context})
-    end
-    networks
-  end
-
-  def self.create(request_body, context, type)
-    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false,"NormaliseSpace"=>2}) : JSON.parse(request_body)
-    if input["networkTemplate"]["href"] #template by reference
-      network_config, routing_group = get_by_reference(input, context)
-    else
-      if input["networkTemplate"]["networkConfig"]["href"] # configuration by reference
-        network_config = NetworkConfiguration.find(context.href_id(input["networkTemplate"]["networkConfig"]["href"],:network_configurations), context)
-      else #configuration by value
-        network_config = get_by_value(request_body, type)
-      end
-      routing_group = RoutingGroup.find(context.href_id(input["networkTemplate"]["routingGroup"]["href"], :routing_groups), context)
-    end
-    params = {:network_config => network_config, :routing_group => routing_group, :name=>input["name"], :description=>input["description"], :env=>context}
-    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
-    context.driver.create_network(context.credentials, params)
-  end
-
-  def self.delete!(id, context)
-    context.driver.delete_network(context.credentials, id)
-  end
-
-  def perform(action, context, &block)
-    begin
-      if context.driver.send(:"#{action.name}_network", context.credentials, self.name)
-        block.callback :success
-      else
-        raise "Operation #{action.name} failed to execute on the Network #{self.name} "
-      end
-    rescue => e
-      block.callback :failure, e.message
-    end
-  end
-
-  private
-
-  def self.get_by_reference(input, context)
-    network_template = NetworkTemplate.find(context.href_id(input["networkTemplate"]["href"], :network_templates), context)
-    network_config = NetworkConfiguration.find(context.href_id(network_template.network_config.href, :network_configurations), context)
-    routing_group = RoutingGroup.find(context.href_id(network_template.routing_group.href, :routing_groups), context)
-    return network_config, routing_group
-  end
-
-  def self.get_by_value(request_body, type)
-    if type == :xml
-      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
-      network_config = NetworkConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["networkTemplate"][0]["networkConfig"][0]))
-    else
-     json = JSON.parse(request_body)
-      network_config = NetworkConfiguration.from_json(JSON.generate(json["networkTemplate"]["networkConfig"]))
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/network_collection.rb b/server/lib/cimi/model/network_collection.rb
deleted file mode 100644
index 836d8e8..0000000
--- a/server/lib/cimi/model/network_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkCollection < CIMI::Model::Base
-
-  act_as_root_entity :network
-
-  array :networks do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.networks_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} NetworkCollection",
-      :networks => Network.all(context).map { |c| { :href => c.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/network_configuration.rb b/server/lib/cimi/model/network_configuration.rb
deleted file mode 100644
index 1b04548..0000000
--- a/server/lib/cimi/model/network_configuration.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkConfiguration < CIMI::Model::Base
-
-  text :access
-
-  text :bandwidth_limit
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    network_configs = []
-    if id==:all
-      network_configs = context.driver.network_configurations(context.credentials, {:env=>context})
-    else
-      network_configs = context.driver.network_configurations(context.credentials, {:env=>context, :id=>id})
-    end
-    network_configs
-  end
-
-  def self.create_from_xml(request_body, context)
-  end
-
-  def self.create_from_json(request_body, context)
-  end
-end
diff --git a/server/lib/cimi/model/network_configuration_collection.rb b/server/lib/cimi/model/network_configuration_collection.rb
deleted file mode 100644
index fd70047..0000000
--- a/server/lib/cimi/model/network_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkConfigurationCollection < CIMI::Model::Base
-
-  act_as_root_entity :network_configuration
-
-  array :network_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.network_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} NetworkConfigurationCollection",
-      :network_configurations => NetworkConfiguration.all(context).map { |c| { :href => c.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/network_template.rb b/server/lib/cimi/model/network_template.rb
deleted file mode 100644
index ce3b990..0000000
--- a/server/lib/cimi/model/network_template.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkTemplate < CIMI::Model::Base
-
-  href :network_config
-
-  href :routing_group
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    network_templates = []
-    if id==:all
-      network_templates = context.driver.network_templates(context.credentials, {:env=>context})
-    else
-      network_templates = context.driver.network_templates(context.credentials, {:env=>context, :id=>id})
-    end
-    network_templates
-  end
-
-end
diff --git a/server/lib/cimi/model/network_template_collection.rb b/server/lib/cimi/model/network_template_collection.rb
deleted file mode 100644
index 6b97b6e..0000000
--- a/server/lib/cimi/model/network_template_collection.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-class CIMI::Model::NetworkTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :network_template
-
-  array :network_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.network_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} NetworkTemplateCollection",
-      :network_templates => NetworkTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group.rb b/server/lib/cimi/model/routing_group.rb
deleted file mode 100644
index d26f4d7..0000000
--- a/server/lib/cimi/model/routing_group.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::RoutingGroup < CIMI::Model::Base
-
-  array :networks do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.routing_groups(context.credentials, {:env=>context})
-    else
-      context.driver.routing_groups(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group_collection.rb b/server/lib/cimi/model/routing_group_collection.rb
deleted file mode 100644
index 1546c80..0000000
--- a/server/lib/cimi/model/routing_group_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::RoutingGroupCollection < CIMI::Model::Base
-
-  act_as_root_entity :routing_group
-
-  array :routing_groups do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.routing_groups_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} RoutingGroupCollection",
-      :routing_groups => RoutingGroup.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group_template.rb b/server/lib/cimi/model/routing_group_template.rb
deleted file mode 100644
index 204a353..0000000
--- a/server/lib/cimi/model/routing_group_template.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::RoutingGroupTemplate < CIMI::Model::Base
-
-  array :networks do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.routing_group_templates(context.credentials, {:env=>context})
-    else
-      context.driver.routing_group_templates(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group_template_collection.rb b/server/lib/cimi/model/routing_group_template_collection.rb
deleted file mode 100644
index 5e7a9ba..0000000
--- a/server/lib/cimi/model/routing_group_template_collection.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-class CIMI::Model::RoutingGroupTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :routing_group_template
-
-  array :routing_group_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.routing_group_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} RoutingGroupTemplateCollection",
-      :routing_group_templates => RoutingGroupTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/schema.rb b/server/lib/cimi/model/schema.rb
deleted file mode 100644
index f301b69..0000000
--- a/server/lib/cimi/model/schema.rb
+++ /dev/null
@@ -1,277 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-# The smarts of converting from XML and JSON into internal objects
-class CIMI::Model::Schema
-
-  #
-  # Attributes describe how we extract values from XML/JSON
-  #
-  class Attribute
-    attr_reader :name, :xml_name, :json_name
-
-    def initialize(name, opts = {})
-      @name = name
-      @xml_name = (opts[:xml_name] || name).to_s.camelize(true)
-      @json_name = (opts[:json_name] || name).to_s.camelize(true)
-    end
-
-    def from_xml(xml, model)
-      model[@name] = xml[@xml_name].first if xml.has_key?(@xml_name)
-    end
-
-    def from_json(json, model)
-      model[@name] = json[@json_name]
-    end
-
-    def to_xml(model, xml)
-      xml[@xml_name] = [model[@name]] if model[@name]
-    end
-
-    def to_json(model, json)
-      json[@json_name] = model[@name] if model and model[@name]
-    end
-  end
-
-  class Scalar < Attribute
-    def initialize(name, opts)
-      @text = opts[:text]
-      if ! [nil, :nested, :direct].include?(@text)
-        raise "text option for scalar must be :nested or :direct"
-      end
-      super(name, opts)
-    end
-
-    def text?; @text; end
-
-    def nested_text?; @text == :nested; end
-
-    def from_xml(xml, model)
-      case @text
-        when :nested then model[@name] = xml[@xml_name].first["content"] if xml[@xml_name]
-        when :direct then model[@name] = xml["content"]
-        else model[@name] = xml[@xml_name]
-      end
-    end
-
-    def to_xml(model, xml)
-      return unless model
-      return unless model[@name]
-      case @text
-        when :nested then xml[@xml_name] = [{ "content" => model[@name] }]
-        when :direct then xml["content"] = model[@name]
-        else xml[@xml_name] = model[@name]
-      end
-    end
-  end
-
-  class Struct < Attribute
-    def initialize(name, opts, &block)
-      content = opts[:content]
-      super(name, opts)
-      @schema = CIMI::Model::Schema.new
-      @schema.instance_eval(&block) if block_given?
-      @schema.scalar(content, :text => :direct) if content
-    end
-
-    def from_xml(xml, model)
-      xml = xml.has_key?(xml_name) ? xml[xml_name].first : {}
-      model[name] = convert_from_xml(xml)
-    end
-
-    def from_json(json, model)
-      json = json.has_key?(json_name) ? json[json_name] : {}
-      model[name] = convert_from_json(json)
-    end
-
-    def to_xml(model, xml)
-      conv = convert_to_xml(model[name])
-      xml[xml_name] = [conv] unless conv.empty?
-    end
-
-    def to_json(model, json)
-      conv = convert_to_json(model[name])
-      json[json_name] = conv unless conv.empty?
-    end
-
-    def convert_from_xml(xml)
-      sub = struct.new
-      @schema.from_xml(xml, sub)
-      sub
-    end
-
-    def convert_from_json(json)
-      sub = struct.new
-      @schema.from_json(json, sub)
-      sub
-    end
-
-    def convert_to_xml(model)
-      xml = {}
-      @schema.to_xml(model, xml)
-      xml
-    end
-
-    def convert_to_json(model)
-      json = {}
-      @schema.to_json(model, json)
-      json
-    end
-
-    private
-    def struct
-      cname = "CIMI_#{json_name.upcase_first}"
-      if ::Struct.const_defined?(cname)
-        ::Struct.const_get(cname)
-      else
-        ::Struct.new("CIMI_#{json_name.upcase_first}",
-                     *@schema.attribute_names)
-      end
-    end
-  end
-
-  class Array < Attribute
-    # For an array :things, we collect all <thing/> elements (XmlSimple
-    # actually does the collecting)
-    def initialize(name, opts = {}, &block)
-      opts[:xml_name] = name.to_s.singularize unless opts[:xml_name]
-      super(name, opts)
-      @struct = Struct.new(name, opts, &block)
-    end
-
-    def from_xml(xml, model)
-      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
-    end
-
-    def from_json(json, model)
-      model[name] = (json[json_name] || []).map { |elt| @struct.convert_from_json(elt) }
-    end
-
-    def to_xml(model, xml)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
-      xml[xml_name] = ary unless ary.empty?
-    end
-
-    def to_json(model, json)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
-      json[json_name] = ary unless ary.empty?
-    end
-  end
-
-  class Hash < Attribute
-
-    def initialize(name, opts = {}, &block)
-      opts[:json_name] = name.to_s.pluralize unless opts[:json_name]
-      super(name, opts)
-      @struct = Struct.new(name, opts, &block)
-    end
-
-    def from_xml(xml, model)
-      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
-    end
-
-    def from_json(json, model)
-      model[name] = (json[json_name] || {}).inject([]) do |result,item|
-        result << @struct.convert_from_json({ 'name' => item[0], 'value' => item[1] })
-      end
-    end
-
-    def to_xml(model, xml)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
-      xml[xml_name] = ary unless ary.empty?
-    end
-
-    def to_json(model, json)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
-      json[json_name] = ary.inject({}) { |result, item| result[item['name']] = item['value']; result } unless ary.empty?
-    end
-  end
-
-  #
-  # The actual Schema class
-  #
-  def initialize
-    @attributes = []
-  end
-
-  def from_xml(xml, model = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.from_xml(xml, model) }
-    model
-  end
-
-  def from_json(json, model = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.from_json(json, model) }
-    model
-  end
-
-  def to_xml(model, xml = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.to_xml(model, xml) }
-    xml
-  end
-
-  def to_json(model, json = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.to_json(model, json) }
-    json
-  end
-
-  def attribute_names
-    @attributes.map { |a| a.name }
-  end
-
-  #
-  # The DSL
-  #
-  # Requires that the class into which this is included has a
-  # +add_attributes!+ method
-  module DSL
-    def href(*args)
-      args.each { |arg| struct(arg) { scalar :href } }
-    end
-
-    def text(*args)
-      args.expand_opts!(:text => :nested)
-      scalar(*args)
-    end
-
-    def scalar(*args)
-      add_attributes!(args, Scalar)
-    end
-
-    def array(name, opts={}, &block)
-      add_attributes!([name, opts], Array, &block)
-    end
-
-    def struct(name, opts={}, &block)
-      add_attributes!([name, opts], Struct, &block)
-    end
-
-    def hash(name, opts={}, &block)
-      add_attributes!([name, opts], Hash, &block)
-    end
-  end
-
-  include DSL
-
-  def add_attributes!(args, attr_klass, &block)
-    raise "The schema has already been used to convert objects" if @attributes.frozen?
-    opts = args.extract_opts!
-    args.each { |arg| @attributes << attr_klass.new(arg, opts, &block) }
-  end
-end
diff --git a/server/lib/cimi/model/volume.rb b/server/lib/cimi/model/volume.rb
deleted file mode 100644
index 0a232d5..0000000
--- a/server/lib/cimi/model/volume.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Volume < CIMI::Model::Base
-
-  struct :capacity do
-    scalar :quantity
-    scalar :units
-  end
-  text :bootable
-  text :supports_snapshots
-  array :snapshots do
-    scalar :ref
-  end
-  text :guest_interface
-  array :meters do
-    scalar :ref
-  end
-  href :eventlog
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    volumes = []
-    opts = ( id == :all ) ? {} : { :id => id }
-    volumes = self.driver.storage_volumes(context.credentials, opts)
-    volumes.collect!{ |volume| from_storage_volume(volume, context) }
-    return volumes.first unless volumes.length > 1
-    return volumes
-  end
-
-  def self.all(context); find(:all, context); end
-
-  def self.create_from_json(json_in, context)
-    json = JSON.parse(json_in)
-    volume_config_id = json["volumeTemplate"]["volumeConfig"]["href"].split("/").last
-    volume_image_id = (json["volumeTemplate"].has_key?("volumeImage") ?
-                json["volumeTemplate"]["volumeImage"]["href"].split("/").last  : nil)
-    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
-  end
-
-  def self.create_from_xml(xml_in, context)
-    xml = XmlSimple.xml_in(xml_in)
-    volume_config_id = xml["volumeTemplate"][0]["volumeConfig"][0]["href"].split("/").last
-    volume_image_id = (xml["volumeTemplate"][0].has_key?("volumeImage") ?
-             xml["volumeTemplate"][0]["volumeImage"][0]["href"].split("/").last  : nil)
-    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
-  end
-
-  def self.delete!(id, context)
-    context.driver.destroy_storage_volume(context.credentials, {:id=>id} )
-  end
-
-  def self.find_to_attach_from_json(json_in, context)
-    json = JSON.parse(json_in)
-    volumes = json["volumes"].map{|v| {:volume=>self.find(v["volume"]["href"].split("/volumes/").last, context),
-                                       :attachment_point=>v["attachmentPoint"]  }}
-  end
-
-  def self.find_to_attach_from_xml(xml_in, context)
-    xml = XmlSimple.xml_in(xml_in)
-    volumes = xml["volume"].map{|v| {:volume => self.find(v["href"].split("/volumes/").last, context),
-                                      :attachment_point=>v["attachmentPoint"] }}
-  end
-
-  private
-
-  def self.create_volume(params, context)
-    volume_config = VolumeConfiguration.find(params[:volume_config_id], context)
-    opts = {:capacity=>volume_config.capacity[:quantity], :snapshot_id=>params[:volume_image_id] }
-    storage_volume = self.driver.create_storage_volume(context.credentials, opts)
-    from_storage_volume(storage_volume, context)
-  end
-
-  def self.from_storage_volume(volume, context)
-    self.new( { :name => volume.id,
-                :description => volume.id,
-                :created => volume.created,
-                :id => context.volume_url(volume.id),
-                :capacity => { :quantity=>volume.capacity, :units=>"gibibyte"  }, #FIXME... units will vary
-                :bootable => "false", #fixme ... will vary... ec2 doesn't expose this
-                :supports_snapshots => "true", #fixme, will vary (true for ec2)
-                :snapshots => [], #fixme...
-                :guest_interface => "",
-                :eventlog => {:href=> "http://eventlogs"},#FIXME
-                :meters => []
-            } )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_collection.rb b/server/lib/cimi/model/volume_collection.rb
deleted file mode 100644
index d5053c7..0000000
--- a/server/lib/cimi/model/volume_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume
-
-  array :volumes do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volumes_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeCollection",
-      :volumes => Volume.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_configuration.rb b/server/lib/cimi/model/volume_configuration.rb
deleted file mode 100644
index 75b37ea..0000000
--- a/server/lib/cimi/model/volume_configuration.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
-
-  text :format
-  struct :capacity do
-    scalar :quantity
-    scalar :units
-  end
-  text :supports_snapshots
-  text :guest_interface
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    volume_configs = []
-    if id == :all
-      #ec2 ebs volumes can 1gb..1tb
-      (1..1000).each do |size|
-        volume_configs << create(size, context)
-      end
-    else
-      volume_configs << create(id, context)
-      return volume_configs.first
-    end
-    return volume_configs
-  end
-
-
-  def self.all(context); find(:all, context); end
-
-  private
-
-  def self.create(size, context)
-    self.new( {
-                :id => context.volume_configuration_url(size),
-                :name => size,
-                :description => "volume configuration with #{size} GiB",
-                :created => Time.now.to_s,
-                :capacity => {:quantity=>size, :units=>"gibibytes"},
-                :supports_snapshots => "true"
-                # FIXME :guest_interface => "NFS"
-            } )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_configuration_collection.rb b/server/lib/cimi/model/volume_configuration_collection.rb
deleted file mode 100644
index ace31bf..0000000
--- a/server/lib/cimi/model/volume_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeConfigurationCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume_configuration
-
-  array :volume_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volume_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeConfigurationCollection",
-      :volume_configurations => VolumeConfiguration.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_image.rb b/server/lib/cimi/model/volume_image.rb
deleted file mode 100644
index 03cc7fd..0000000
--- a/server/lib/cimi/model/volume_image.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeImage < CIMI::Model::Base
-
-  href :image_location
-  text :image_data
-  text :bootable
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    storage_snapshots = []
-    opts = ( id==:all  ) ? {}  : { :id=>id }
-    storage_snapshots = self.driver.storage_snapshots(context.credentials, opts)
-    storage_snapshots.collect!{ |snapshot| from_storage_snapshot(snapshot, context) }
-    return storage_snapshots.first unless storage_snapshots.length > 1
-    return storage_snapshots
-  end
-
-  def self.all(context); find(:all, context); end
-
-  private
-
-  def self.from_storage_snapshot(snapshot, context)
-    self.new( {
-               :name => snapshot.id,
-               :description => snapshot.id,
-               :created => snapshot.created,
-               :id => context.volume_image_url(snapshot.id),
-               :image_location => {:href=>context.volume_url(snapshot.storage_volume_id)},
-               :bootable => "false"  #FIXME
-            } )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_image_collection.rb b/server/lib/cimi/model/volume_image_collection.rb
deleted file mode 100644
index 0172c04..0000000
--- a/server/lib/cimi/model/volume_image_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeImageCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume_image
-
-  array :volume_images do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volume_images_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeImageCollection",
-      :volume_images => VolumeImage.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_template.rb b/server/lib/cimi/model/volume_template.rb
deleted file mode 100644
index b9c82db..0000000
--- a/server/lib/cimi/model/volume_template.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeTemplate < CIMI::Model::Base
-
-  href :volume_config
-  href :volume_image
-  array :operations do
-    scalar :rel, :href
-  end
-end
diff --git a/server/lib/cimi/model/volume_template_collection.rb b/server/lib/cimi/model/volume_template_collection.rb
deleted file mode 100644
index 6b6e4ac..0000000
--- a/server/lib/cimi/model/volume_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume_template
-
-  array :volume_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volume_template_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeTemplateCollection",
-      :volume_templates => VolumeTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp.rb b/server/lib/cimi/model/vsp.rb
deleted file mode 100644
index 40a526f..0000000
--- a/server/lib/cimi/model/vsp.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSP < CIMI::Model::Base
-
-  text :state
-
-  href :network
-
-  text :bandwidth_reservation
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  href :event_log
-
-  array :meters do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.vsps(context.credentials, {:env=>context})
-    else
-      context.driver.vsps(context.credentials, {:id=>id, :env=>context})
-    end
-  end
-
-  def self.create(request_body, context, type)
-    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
-    if input["vspTemplate"]["href"] #template by reference
-      vsp_config, network = get_by_reference(input, context)
-    else
-      if input["vspTemplate"]["vspConfig"]["href"] # configuration by reference
-        vsp_config = VSPConfiguration.find(context.href_id(input["vspTemplate"]["vspConfig"]["href"],:vsp_configurations), context)
-      else #configuration by value
-        vsp_config = get_by_value(request_body, type)
-      end
-      network = Network.find(context.href_id(input["vspTemplate"]["network"]["href"], :networks), context)
-    end
-    params = {:vsp_config => vsp_config, :network => network, :name=>input["name"], :description=>input["description"], :env=>context}
-    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
-    context.driver.create_vsp(context.credentials, params)
-  end
-
-  def self.delete!(id, context)
-    context.driver.delete_vsp(context.credentials, id)
-  end
-
-  def perform(action, context, &block)
-    begin
-      if context.driver.send(:"#{action.name}_vsp", context.credentials, self.name)
-        block.callback :success
-      else
-        raise "Operation #{action.name} failed to execute on the VSP #{self.name} "
-      end
-    rescue => e
-      block.callback :failure, e.message
-    end
-  end
-
-
-  private
-
-  def self.get_by_reference(input, context)
-    vsp_template = VSPTemplate.find(context.href_id(input["vspTemplate"]["href"], :vsp_templates), context)
-    vsp_config = VSPConfiguration.find(context.href_id(vsp_template.vsp_config.href, :vsp_configurations), context)
-    network = Network.find(context.href_id(vsp_template.network.href, :networks), context)
-    return vsp_config, network
-  end
-
-  def self.get_by_value(request_body, type)
-    if type == :xml
-      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
-      vsp_config = VSPConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["vspTemplate"][0]["vspConfig"][0]))
-    else
-     json = JSON.parse(request_body)
-      vsp_config = VSPConfiguration.from_json(JSON.generate(json["vspTemplate"]["vspConfig"]))
-    end
-  end
-end
diff --git a/server/lib/cimi/model/vsp_collection.rb b/server/lib/cimi/model/vsp_collection.rb
deleted file mode 100644
index 6f659e1..0000000
--- a/server/lib/cimi/model/vsp_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPCollection < CIMI::Model::Base
-
-  CIMI::Model.register_as_root_entity! "VSPs"
-
-  array :vsps do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.vsps_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VSPCollection",
-      :vsps => VSP.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_configuration.rb b/server/lib/cimi/model/vsp_configuration.rb
deleted file mode 100644
index c9a9bf3..0000000
--- a/server/lib/cimi/model/vsp_configuration.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPConfiguration < CIMI::Model::Base
-
-  text :bandwidth_reservation
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.vsp_configurations(context.credentials, {:env=>context})
-    else
-      context.driver.vsp_configurations(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_configuration_collection.rb b/server/lib/cimi/model/vsp_configuration_collection.rb
deleted file mode 100644
index addff1c..0000000
--- a/server/lib/cimi/model/vsp_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPConfigurationCollection < CIMI::Model::Base
-
-  CIMI::Model.register_as_root_entity! "VSPConfigurations"
-
-  array :vsp_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.vsp_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VSPConfigurationCollection",
-      :vsp_configurations => VSPConfiguration.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_template.rb b/server/lib/cimi/model/vsp_template.rb
deleted file mode 100644
index f1b8078..0000000
--- a/server/lib/cimi/model/vsp_template.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPTemplate < CIMI::Model::Base
-
-  href :network
-
-  href :vsp_config
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.vsp_templates(context.credentials, {:env=>context})
-    else
-      context.driver.vsp_templates(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_template_collection.rb b/server/lib/cimi/model/vsp_template_collection.rb
deleted file mode 100644
index 4acb74e..0000000
--- a/server/lib/cimi/model/vsp_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPTemplateCollection < CIMI::Model::Base
-
-  CIMI::Model.register_as_root_entity! "VSPTemplates"
-
-  array :vsp_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.vsp_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VSPTemplateCollection",
-      :vsp_templates => VSPTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
new file mode 100644
index 0000000..b0793ee
--- /dev/null
+++ b/server/lib/cimi/models.rb
@@ -0,0 +1,75 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless require_relatived by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+require_relative '../deltacloud/drivers/features'
+
+# Declare namespace for CIMI models
+#
+
+module CIMI
+  module Model; end
+
+  class FakeCollection
+    extend Sinatra::Rabbit::Features
+    include Deltacloud::InstanceFeatures
+  end
+end
+
+require_relative './models/schema'
+require_relative './models/base'
+require_relative './models/errors'
+require_relative './models/entity_metadata'
+require_relative './models/entity_metadata_collection'
+require_relative './models/cloud_entry_point'
+require_relative './models/machine_template'
+require_relative './models/machine_image'
+require_relative './models/machine_configuration'
+require_relative './models/action'
+require_relative './models/machine'
+require_relative './models/volume'
+require_relative './models/machine_admin'
+require_relative './models/volume_configuration'
+require_relative './models/volume_image'
+require_relative './models/volume_template'
+require_relative './models/machine_template_collection'
+require_relative './models/machine_image_collection'
+require_relative './models/machine_configuration_collection'
+require_relative './models/machine_collection'
+require_relative './models/volume_collection'
+require_relative './models/machine_admin_collection'
+require_relative './models/volume_configuration_collection'
+require_relative './models/volume_image_collection'
+require_relative './models/volume_template_collection'
+require_relative './models/network'
+require_relative './models/network_collection'
+require_relative './models/network_configuration'
+require_relative './models/network_configuration_collection'
+require_relative './models/network_template'
+require_relative './models/network_template_collection'
+require_relative './models/routing_group'
+require_relative './models/routing_group_collection'
+require_relative './models/routing_group_template'
+require_relative './models/routing_group_template_collection'
+require_relative './models/vsp'
+require_relative './models/vsp_collection'
+require_relative './models/vsp_configuration'
+require_relative './models/vsp_configuration_collection'
+require_relative './models/vsp_template'
+require_relative './models/vsp_template_collection'
+require_relative './models/address'
+require_relative './models/address_collection'
+require_relative './models/address_template'
+require_relative './models/address_template_collection'
diff --git a/server/lib/cimi/models/action.rb b/server/lib/cimi/models/action.rb
new file mode 100644
index 0000000..c1c9908
--- /dev/null
+++ b/server/lib/cimi/models/action.rb
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Action < CIMI::Model::Base
+
+  text :action
+
+  def name
+    action.split('/').last.strip.intern
+  end
+
+end
diff --git a/server/lib/cimi/models/address.rb b/server/lib/cimi/models/address.rb
new file mode 100644
index 0000000..f9e10a1
--- /dev/null
+++ b/server/lib/cimi/models/address.rb
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Address < CIMI::Model::Base
+
+  text :ip
+
+  text :hostname
+
+  text :allocation
+
+  text :default_gateway
+
+  text :dns
+
+  text :mac_address
+
+  text :protocol
+
+  text :mask
+
+  href :network
+
+  href :resource
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.addresses(context.credentials, {:env=>context})
+    else
+      context.driver.addresses(context.credentials, {:id=>id, :env=>context})
+    end
+  end
+
+  def self.create(request_body, context, type)
+    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
+    if input["addressTemplate"]["href"] #by reference
+      address_template = CIMI::Model::AddressTemplate.find(context.href_id(input["addressTemplate"]["href"], :address_templates), context)
+    else
+      case type
+        when :json
+          address_template = CIMI::Model::AddressTemplate.from_json(JSON.generate(input["addressTemplate"]))
+        when :xml
+          xml = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
+          address_template = CIMI::Model::AddressTemplate.from_xml(XmlSimple.xml_out(xml["addressTemplate"][0]))
+      end
+    end
+    params = {:name=>input["name"], :description=>input["description"], :address_template=>address_template, :env=>context }
+    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
+    context.driver.create_address(context.credentials, params)
+  end
+
+  def self.delete!(id, context)
+    context.driver.delete_address(context.credentials, id)
+  end
+
+end
diff --git a/server/lib/cimi/models/address_collection.rb b/server/lib/cimi/models/address_collection.rb
new file mode 100644
index 0000000..eef6c51
--- /dev/null
+++ b/server/lib/cimi/models/address_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::AddressCollection < CIMI::Model::Base
+
+  act_as_root_entity :address
+
+  array :addresses do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.addresses_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} AddressCollection",
+      :addresses => CIMI::Model::Address.all(context).map { |addr| { :href => addr.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/address_template.rb b/server/lib/cimi/models/address_template.rb
new file mode 100644
index 0000000..9d2c409
--- /dev/null
+++ b/server/lib/cimi/models/address_template.rb
@@ -0,0 +1,54 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::AddressTemplate < CIMI::Model::Base
+
+  text :ip
+
+  text :hostname
+
+  text :allocation
+
+  text :default_gateway
+
+  text :dns
+
+  text :mac_address
+
+  text :protocol
+
+  text :mask
+
+  href :network
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.address_templates(context.credentials, {:env=>context})
+    else
+      context.driver.address_templates(context.credentials, {:id=>id, :env=>context})
+    end
+  end
+
+  def self.create(request_body, context, type)
+  end
+
+  def self.delete!(id, context)
+  end
+
+end
diff --git a/server/lib/cimi/models/address_template_collection.rb b/server/lib/cimi/models/address_template_collection.rb
new file mode 100644
index 0000000..3bb95cd
--- /dev/null
+++ b/server/lib/cimi/models/address_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::AddressTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :address_template
+
+  array :address_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.address_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} AddressTemplateCollection",
+      :address_templates => CIMI::Model::AddressTemplate.all(context).map { |addr| { :href => addr.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
new file mode 100644
index 0000000..16812ac
--- /dev/null
+++ b/server/lib/cimi/models/base.rb
@@ -0,0 +1,249 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require 'xmlsimple'
+require 'json'
+
+# The base class for any CIMI object that we either read from a request or
+# write as a response. This class handles serializing/deserializing XML and
+# JSON into a common form.
+#
+# == Defining the schema
+#
+# The conversion of XML and JSON into internal objects is based on a schema
+# that is defined through a DSL:
+#
+#   class Machine < CIMI::Model::Base
+#     text :status
+#     href :meter
+#     array :volumes do
+#       scalar :href, :attachment_point, :protocol
+#     end
+#   end
+#
+# The DSL automatically takes care of converting identifiers from their
+# underscored form to the camel-cased form used by CIMI. The above class
+# can be used in the following way:
+#
+#   machine = Machine.from_xml(some_xml)
+#   if machine.status == "UP"
+#     ...
+#   end
+#   sda = machine.volumes.find { |v| v.attachment_point == "/dev/sda" }
+#   handle_meter(machine.meter.href)
+#
+# The keywords for the DSL are
+#   [scalar(names, ...)]
+#     Define a scalar attribute; in JSON, this is represented as a string
+#     property. In XML, this can be represented in a number of ways,
+#     depending on whether the option :text is set:
+#       * :text not set: attribute on the enclosing element
+#       * :text == :direct: the text content of the enclosing element
+#       * :text == :nested: the text content of an element +<name>...</name>+
+#   [text(names)]
+#     A shorthand for +scalar(names, :text => :nested)+, i.e., for
+#     attributes that in XML are represented by their own tags
+#   [href(name)]
+#     A shorthand for +struct name { scalar :href }+; in JSON, this is
+#     represented as +{ name: { "href": string } }+, and in XML as +<name
+#     href="..."/>+
+#   [struct(name, opts, &block)]
+#     A structured subobject; the block defines the schema of the
+#     subobject. The +:content+ option can be used to specify the attribute
+#     that should receive the content of hte corresponding XML element
+#   [array(name, opts, &block)]
+#     An array of structured subobjects; the block defines the schema of
+#     the subobjects.
+
+module CIMI::Model
+
+  def self.register_as_root_entity!(name)
+    @root_entities ||= []
+    @root_entities << name
+    unless CIMI::Model::CloudEntryPoint.href_defined?(name)
+      CIMI::Model::CloudEntryPoint.send(:href, name.underscore)
+    end
+  end
+
+  def self.root_entities
+    @root_entities || []
+  end
+
+end
+
+class CIMI::Model::Base
+
+  #
+  # We keep the values of the attributes in a hash
+  #
+  attr_reader :attribute_values
+
+  # Keep the list of all attributes in an array +attributes+; for each
+  # attribute, we also define a getter and a setter to access/change the
+  # value for that attribute
+  class << self
+    def base_schema
+      @schema ||= CIMI::Model::Schema.new
+    end
+
+    def clone_base_schema
+      @schema_duped = true
+      @schema = Marshal::load(Marshal.dump(superclass.base_schema))
+    end
+
+    def base_schema_cloned?
+      @schema_duped
+    end
+
+    private :'clone_base_schema', :'base_schema_cloned?'
+
+    def inherited(child)
+      child.instance_eval do
+        def schema
+          base_schema_cloned? ? @schema : clone_base_schema
+        end
+      end
+    end
+
+    def add_attributes!(names, attr_klass, &block)
+      if self.respond_to? :schema
+        schema.add_attributes!(names, attr_klass, &block)
+      else
+        base_schema.add_attributes!(names, attr_klass, &block)
+      end
+      names.each do |name|
+        define_method(name) { @attribute_values[name] }
+        define_method(:"#{name}=") { |newval| @attribute_values[name] = newval }
+      end
+    end
+
+    # Return Array of links to current CIMI object
+    def all_uri(context)
+      self.all(context).map { |e| { :href => e.id } }
+    end
+  end
+
+  extend CIMI::Model::Schema::DSL
+
+  def [](a)
+    @attribute_values[a]
+  end
+
+  def []=(a, v)
+    @attribute_values[a] = v
+  end
+
+  #
+  # Factory methods
+  #
+  def initialize(values = {})
+    @attribute_values = values
+  end
+
+  # Construct a new object from the XML representation +xml+
+  def self.from_xml(text)
+    xml = XmlSimple.xml_in(text, :force_content => true)
+    model = self.new
+    @schema.from_xml(xml, model)
+    model
+  end
+
+  # Construct a new object
+  def self.from_json(text)
+    json = JSON::parse(text)
+    model = self.new
+    @schema.from_json(json, model)
+    model
+  end
+
+  #
+  # Serialize
+  #
+
+  def self.xml_tag_name
+    self.name.split("::").last
+  end
+
+  def self.to_json(model)
+    JSON::unparse(@schema.to_json(model))
+  end
+
+  def self.to_xml(model)
+    xml = @schema.to_xml(model)
+    xml["xmlns"] = "http://www.dmtf.org/cimi"
+    XmlSimple.xml_out(xml, :root_name => xml_tag_name)
+  end
+
+  def to_json
+    self.class.to_json(self)
+  end
+
+  def to_xml
+    self.class.to_xml(self)
+  end
+
+  #
+  # Common attributes for all resources
+  #
+  text :id, :name, :description, :created
+
+  # FIXME: this doesn't match with JSON
+  hash :property, :content => :value do
+    scalar :name
+  end
+
+  def self.act_as_root_entity(name=nil)
+    if name
+      name = name.to_s.camelize.pluralize
+    else
+      name = xml_tag_name.pluralize.uncapitalize
+    end
+    CIMI::Model.register_as_root_entity! name
+  end
+
+  def self.all(_self); find(:all, _self); end
+
+  def filter_by(filter_opts)
+    return self if filter_opts.nil?
+    return filter_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
+    case filter_opts
+      when /^([\w\_]+)$/ then filter_attributes([$1.intern])
+      when /^([\w\_]+)\[(\d+\-\d+)\]$/ then filter_by_arr_range($1.intern, $2)
+      when /^([\w\_]+)\[(\d+)\]$/ then filter_by_arr_index($1.intern, $2)
+      else self
+    end
+  end
+
+  private
+
+  def filter_attributes(attr_list)
+    attrs = attr_list.inject({}) do |result, attr|
+      result[attr] = self.send(attr) if self.respond_to?(attr)
+      result
+    end
+    self.class.new(attrs)
+  end
+
+  def filter_by_arr_index(attr, filter)
+    return self unless self.respond_to?(attr)
+    self.class.new(attr => [self.send(attr)[filter.to_i]])
+  end
+
+  def filter_by_arr_range(attr, filter)
+    return self unless self.respond_to?(attr)
+    filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
+    self.class.new(attr => self.send(attr)[filter])
+  end
+end
diff --git a/server/lib/cimi/models/cloud_entry_point.rb b/server/lib/cimi/models/cloud_entry_point.rb
new file mode 100644
index 0000000..ffe1ef5
--- /dev/null
+++ b/server/lib/cimi/models/cloud_entry_point.rb
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
+
+  array :entity_metadata do
+    scalar :href
+  end
+
+  def self.create(context)
+    self.new(entities(context).merge({
+      :name => context.driver.name,
+      :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
+      :id => context.cloudEntryPoint_url,
+      :created => Time.now,
+      :entity_metadata => CIMI::Model::EntityMetadata.all_uri(context)
+    }))
+  end
+
+  # Return an Hash of the CIMI root entities used in CloudEntryPoint
+  def self.entities(context)
+    CIMI::Model.root_entities.inject({}) do |result, entity|
+      result[entity.underscore] = { :href => context.send(:"#{entity.underscore}_url") }
+      result
+    end
+  end
+
+  private
+
+  def self.href_defined?(entity)
+    true if schema.attribute_names.include? entity.underscore
+  end
+
+end
diff --git a/server/lib/cimi/models/entity_metadata.rb b/server/lib/cimi/models/entity_metadata.rb
new file mode 100644
index 0000000..5455c75
--- /dev/null
+++ b/server/lib/cimi/models/entity_metadata.rb
@@ -0,0 +1,84 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class CIMI::Model::EntityMetadata < CIMI::Model::Base
+
+  text :type_uri
+
+  array :attributes do
+    scalar :name
+    scalar :namespace
+    scalar :type
+    scalar :required
+    scalar :constraints
+  end
+
+  array :operations do
+    scalar :name
+    scalar :uri
+    scalar :description
+    scalar :method
+    scalar :input_message
+    scalar :output_message
+  end
+
+  def self.find(id, context)
+    entity_metadata = []
+    if id == :all
+      CIMI::Model.root_entities.each do |entity|
+        entity_class = CIMI::Model.const_get("#{entity.singularize}")
+        entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?(:create_entity_metadata)
+      end
+      return entity_metadata
+    else
+      entity_class = CIMI::Model.const_get("#{id.camelize}")
+      if entity_class.respond_to?(:create_entity_metadata)
+        entity_class.create_entity_metadata(context)
+      end
+    end
+  end
+
+  def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
+    deltacloud_features = context.driver.class.features_for(dcloud_entity)
+    metadata_attributes = deltacloud_features.map{|f| attributes_from_feature(f)}
+    from_feature(cimi_entity, context, metadata_attributes.flatten!)
+  end
+
+  def includes_attribute?(attribute)
+    self.attributes.any?{|attr| attr[:name] == attribute}
+  end
+
+  private
+
+  def self.attributes_from_feature(feature)
+    feature = CIMI::FakeCollection.feature(feature)
+    feature.operations.first.params_array.map do |p|
+      {
+        :name=> p.name,
+        :type=> "xs:string",
+        :required=> p.required? ? "true" : "false",
+        :constraints=> (feature.constraints.empty? ? (feature.description.nil? ? "" : feature.description): feature.constraints)
+      }
+    end
+  end
+
+  def self.from_feature(cimi_entity, context, metadata_attributes)
+    self.new(:name => cimi_entity, :uri=>"#{context.entity_metadata_url}/#{cimi_entity.underscore}",
+             :type_uri=> context.send("#{cimi_entity.pluralize.underscore}_url"),
+             :attributes => metadata_attributes)
+  end
+
+end
diff --git a/server/lib/cimi/models/entity_metadata_collection.rb b/server/lib/cimi/models/entity_metadata_collection.rb
new file mode 100644
index 0000000..595b502
--- /dev/null
+++ b/server/lib/cimi/models/entity_metadata_collection.rb
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::EntityMetadataCollection < CIMI::Model::Base
+
+  array :entity_metadata do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.entity_metadata_url,
+      :name => 'default',
+      :created => Time.now,
+      :entity_metadata => CIMI::Model::EntityMetadata.all_uri(context)
+   )
+  end
+
+end
diff --git a/server/lib/cimi/models/errors.rb b/server/lib/cimi/models/errors.rb
new file mode 100644
index 0000000..7c090ed
--- /dev/null
+++ b/server/lib/cimi/models/errors.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Model
+
+  class NotFound < StandardError
+    attr_accessor :code
+
+    def initialize
+      super("Requested Entity Not Found")
+      self.code = 404
+    end
+
+  end
+
+  class BadRequest < StandardError
+    attr_accessor :code
+    def initialize(msg="")
+      super(msg)
+      self.code=400
+    end
+  end
+
+  class NotImplemented < StandardError
+    attr_accessor :code
+
+    def initialize
+      super("Requested operation is not implemented by backend provider")
+      self.code = 501
+    end
+
+  end
+
+end
+
+
diff --git a/server/lib/cimi/models/machine.rb b/server/lib/cimi/models/machine.rb
new file mode 100644
index 0000000..0540bd8
--- /dev/null
+++ b/server/lib/cimi/models/machine.rb
@@ -0,0 +1,227 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Machine < CIMI::Model::Base
+
+  text :state
+  text :cpu
+
+  struct :memory do
+    scalar :quantity
+    scalar :units
+  end
+
+  href :event_log
+
+  array :disks do
+    struct :capacity do
+      scalar :quantity
+      scalar :units
+    end
+    scalar :format
+    scalar :attachment_point
+  end
+
+  array :volumes do
+    scalar :href
+    scalar :protocol
+    scalar :attachment_point
+  end
+
+  array :network_interfaces do
+    href :vsp
+    text :hostname, :mac_address, :state, :protocol, :allocation
+    text :address, :default_gateway, :dns, :max_transmission_unit
+  end
+
+  array :meters do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    instances = []
+    if id == :all
+      instances = context.driver.instances(context.credentials)
+      instances.map { |instance| from_instance(instance, context) }.compact
+    else
+      instance = context.driver.instance(context.credentials, :id => id)
+      raise CIMI::Model::NotFound unless instance
+      from_instance(instance, context)
+    end
+  end
+
+  def self.create_from_json(body, context)
+    json = JSON.parse(body)
+    hardware_profile_id = xml['machineTemplate']['machineConfig']["href"].split('/').last
+    image_id = xml['machineTemplate']['machineImage']["href"].split('/').last
+    instance = context.create_instance(context.credentials, image_id, { :hwp_id => hardware_profile_id })
+    from_instance(instance, context)
+  end
+
+  def self.create_from_xml(body, context)
+    xml = XmlSimple.xml_in(body)
+    machine_template = xml['machineTemplate'][0]
+    hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
+    image_id = machine_template['machineImage'][0]["href"].split('/').last
+    additional_params = {}
+    additional_params[:name] =xml['name'][0] if xml['name']
+    if machine_template.has_key? 'machineAdmin'
+      additional_params[:keyname] = machine_template['machineAdmin'][0]["href"].split('/').last
+    end
+    instance = context.driver.create_instance(context.credentials, image_id, {
+      :hwp_id => hardware_profile_id
+    }.merge(additional_params))
+    from_instance(instance, context)
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_instance", context.credentials, self.name)
+        block.callback :success
+      else
+        raise "Operation failed to execute on given Machine"
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_instance(context.credentials, id)
+  end
+
+  def self.create_entity_metadata(context)
+    cimi_entity = self.name.split("::").last
+    metadata = CIMI::Model::EntityMetadata.metadata_from_deltacloud_features(cimi_entity, :instances, context)
+    unless metadata.includes_attribute?(:name)
+      metadata.attributes << {:name=>"name", :required=>"false",
+                   :constraints=>"Determined by the cloud provider", :type=>"xs:string"}
+    end
+    metadata
+  end
+
+  def self.attach_volumes(volumes, context)
+    volumes.each do |vol|
+      context.driver.attach_storage_volume(context.credentials,
+      {:id=>vol[:volume].name, :instance_id=>context.params[:id], :device=>vol[:attachment_point]})
+    end
+    self.find(context.params[:id], context)
+  end
+
+  def self.detach_volumes(volumes, context)
+    volumes.each do |vol|
+      context.driver.detach_storage_volume(context.credentials, {:id=>vol[:volume].name, :instance_id => context.params[:id]})
+    end
+    self.find(context.params[:id], context)
+  end
+
+  private
+
+  def self.from_instance(instance, context)
+    cpu =  memory = disks = (instance.instance_profile.id == "opaque")? "n/a" : nil
+    self.new(
+      :name => instance.id,
+      :description => instance.name,
+      :created => instance.launch_time,
+      :id => context.machine_url(instance.id),
+      :state => convert_instance_state(instance.state),
+      :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
+      :memory => memory || convert_instance_memory(instance.instance_profile, context),
+      :disks => disks || convert_instance_storage(instance.instance_profile, context),
+      :network_interfaces => convert_instance_addresses(instance),
+      :operations => convert_instance_actions(instance, context),
+      :volumes=>convert_storage_volumes(instance, context),
+      :property => convert_instance_properties(instance, context)
+    )
+  end
+
+  # FIXME: This will convert 'RUNNING' state to 'STARTED'
+  # which is defined in CIMI (p65)
+  #
+  def self.convert_instance_state(state)
+    ('RUNNING' == state) ? 'STARTED' : state
+  end
+
+  def self.convert_instance_properties(instance, context)
+    properties = []
+    properties << { :name => :machine_image, :value => context.machine_image_url(instance.image_id) }
+    if instance.respond_to? :keyname
+      properties << { :name => :machine_admin, :value => context.machine_admin_url(instance.keyname) }
+    end
+    properties
+  end
+
+  def self.convert_instance_cpu(profile, context)
+    cpu_override = profile.overrides.find { |p, v| p == :cpu }
+    if cpu_override.nil?
+      CIMI::Model::MachineConfiguration.find(profile.id, context).cpu
+    else
+      cpu_override[1]
+    end
+  end
+
+  def self.convert_instance_memory(profile, context)
+    machine_conf = CIMI::Model::MachineConfiguration.find(profile.name, context)
+    memory_override = profile.overrides.find { |p, v| p == :memory }
+    {
+      :quantity => memory_override.nil? ? machine_conf.memory[:quantity] : memory_override[1],
+      :units => machine_conf.memory[:units]
+    }
+  end
+
+  def self.convert_instance_storage(profile, context)
+    machine_conf = CIMI::Model::MachineConfiguration.find(profile.name, context)
+    storage_override = profile.overrides.find { |p, v| p == :storage }
+    [
+      { :capacity => {
+          :quantity => storage_override.nil? ? machine_conf.disks.first[:capacity][:quantity] : storage_override[1],
+          :units => machine_conf.disks.first[:capacity][:units]
+        }
+      }
+    ]
+  end
+
+  def self.convert_instance_addresses(instance)
+    (instance.public_addresses + instance.private_addresses).collect do |address|
+      {
+        :hostname => address.is_hostname? ? address : nil,
+        :mac_address => address.is_mac? ? address : nil,
+        :state => 'Active',
+        :protocol => 'IPv4',
+        :address => address.is_ipv4? ? address : nil,
+        :allocation => 'Static'
+      }
+    end
+  end
+
+  def self.convert_instance_actions(instance, context)
+    instance.actions.collect do |action|
+      action = :destroy if action == :delete # In CIMI destroy operation become delete
+      action = :restart if action == :reboot  # In CIMI reboot operation become restart
+      { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://www.dmtf.org/cimi/action/#{action}" }
+    end
+  end
+
+  def self.convert_storage_volumes(instance, context)
+    instance.storage_volumes ||= [] #deal with nilpointers
+    instance.storage_volumes.map{|vol| {:href=>context.volume_url(vol.keys.first),
+                                       :attachment_point=>vol.values.first} }
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_admin.rb b/server/lib/cimi/models/machine_admin.rb
new file mode 100644
index 0000000..fed7c80
--- /dev/null
+++ b/server/lib/cimi/models/machine_admin.rb
@@ -0,0 +1,59 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineAdmin < CIMI::Model::Base
+
+  text :username
+  text :password
+  text :key
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id == :all
+      keys = context.driver.keys(context.credentials)
+      keys.map { |key| from_key(key, context) }
+    else
+      key = context.driver.key(context.credentials, :id => id)
+      from_key(key, context)
+    end
+  end
+
+  def self.create_from_xml(body, context)
+    machine_admin = MachineAdmin.from_xml(body)
+    key = context.driver.create_key(context.credentials, :key_name => machine_admin.name)
+    from_key(key, context)
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_key(context.credentials, :id => id)
+  end
+
+  private
+
+  def self.from_key(key, context)
+    self.new(
+      :name => key.id,
+      :username => key.username,
+      :password => key.is_password? ? key.password : key.fingerprint,
+      :key => key.is_key? ? key.pem_rsa_key : nil,
+      :id => context.machine_admin_url(key.id),
+      :created => Time.now
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_admin_collection.rb b/server/lib/cimi/models/machine_admin_collection.rb
new file mode 100644
index 0000000..08c1559
--- /dev/null
+++ b/server/lib/cimi/models/machine_admin_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineAdminCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_admin
+
+  array :machine_admins do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_admins_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineAdminCollection",
+      :machine_admins => CIMI::Model::MachineAdmin.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_collection.rb b/server/lib/cimi/models/machine_collection.rb
new file mode 100644
index 0000000..9154aa9
--- /dev/null
+++ b/server/lib/cimi/models/machine_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine
+
+  array :machines do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machines_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineCollection",
+      :machines => CIMI::Model::Machine.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_configuration.rb b/server/lib/cimi/models/machine_configuration.rb
new file mode 100644
index 0000000..f9d98f2
--- /dev/null
+++ b/server/lib/cimi/models/machine_configuration.rb
@@ -0,0 +1,70 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineConfiguration < CIMI::Model::Base
+
+  struct :memory do
+    scalar :quantity
+    scalar :units
+  end
+
+  text :cpu
+
+  array :disks do
+    struct :capacity do
+      scalar :quantity
+      scalar :units
+    end
+    scalar :format
+    scalar :attachment_point
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    profiles = []
+    if id == :all
+      profiles = context.driver.hardware_profiles(context.credentials)
+      profiles.map { |profile| from_hardware_profile(profile, context) }.compact
+    else
+      profile = context.driver.hardware_profile(context.credentials, id)
+      from_hardware_profile(profile, context)
+    end
+  end
+
+  private
+
+  def self.from_hardware_profile(profile, context)
+    # We accept just profiles with all properties set
+    return unless profile.memory or profile.cpu or profile.storage
+    memory = profile.memory.value || profile.memory.default
+    cpu = profile.cpu.value || profile.cpu.default
+    storage = profile.storage.value || profile.storage.default
+    machine_hash = {
+      :name => profile.name,
+      :description => "Machine Configuration with #{memory} #{profile.memory.unit} "+
+        "of memory and #{cpu} CPU",
+      :cpu => cpu,
+      :created => Time.now.to_s,  # FIXME: DC hardware_profile has no mention about created_at
+      :memory => { :quantity => profile.memory.value || profile.memory.default, :units => profile.memory.unit },
+      :disks => [ { :capacity => { :quantity => profile.storage.value || profile.storage.default, :units => profile.storage.unit } } ],
+      :id => context.machine_configuration_url(profile.name)
+    }
+    self.new(machine_hash)
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_configuration_collection.rb b/server/lib/cimi/models/machine_configuration_collection.rb
new file mode 100644
index 0000000..6d7ebad
--- /dev/null
+++ b/server/lib/cimi/models/machine_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineConfigurationCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_configuration
+
+  array :machine_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineConfigurationCollection",
+      :machine_configurations => CIMI::Model::MachineConfiguration.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_image.rb b/server/lib/cimi/models/machine_image.rb
new file mode 100644
index 0000000..7389475
--- /dev/null
+++ b/server/lib/cimi/models/machine_image.rb
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineImage < CIMI::Model::Base
+
+  href :image_location
+  text :image_data
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    images = []
+    if id == :all
+      images = context.driver.images(context.credentials)
+      images.map { |image| from_image(image, context) }
+    else
+      image = context.driver.image(context.credentials, :id => id)
+      from_image(image, context)
+    end
+  end
+
+  def self.from_image(image, context)
+    self.new(
+      :name => image.id,
+      :id => context.machine_image_url(image.id),
+      :description => image.description,
+      :created => Time.now.to_s,
+      :image_location => { :href => "#{context.driver.name}://#{image.id}" } # FIXME
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_image_collection.rb b/server/lib/cimi/models/machine_image_collection.rb
new file mode 100644
index 0000000..70bdc7b
--- /dev/null
+++ b/server/lib/cimi/models/machine_image_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineImageCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_image
+
+  array :machine_images do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_images_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineImageCollection",
+      :machine_images => CIMI::Model::MachineImage.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_template.rb b/server/lib/cimi/models/machine_template.rb
new file mode 100644
index 0000000..8a88052
--- /dev/null
+++ b/server/lib/cimi/models/machine_template.rb
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineTemplate < CIMI::Model::Base
+
+  href :machine_config
+  href :machine_image
+  href :machine_admin
+
+  array :volumes do
+    scalar :href
+    scalar :protocol
+    scalar :attachment_point
+  end
+
+  array :volume_templates do
+    scalar :href, :attachment_point, :protocol
+  end
+
+  array :network_interfaces do
+    href :vsp
+    text :hostname, :mac_address, :state, :protocol, :allocation
+    text :address, :default_gateway, :dns, :max_transmission_unit
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+end
diff --git a/server/lib/cimi/models/machine_template_collection.rb b/server/lib/cimi/models/machine_template_collection.rb
new file mode 100644
index 0000000..d2a3f23
--- /dev/null
+++ b/server/lib/cimi/models/machine_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_template
+
+  array :machine_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_template_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineTemplateCollection",
+      :machine_templates => CIMI::Model::MachineTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/network.rb b/server/lib/cimi/models/network.rb
new file mode 100644
index 0000000..3d9c7ed
--- /dev/null
+++ b/server/lib/cimi/models/network.rb
@@ -0,0 +1,109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Network < CIMI::Model::Base
+
+  text :state
+
+  text :access
+
+  text :bandwidth_limit
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  href :routing_group
+
+  href :event_log
+
+  array :meters do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    networks=[]
+    if id==:all
+      networks = context.driver.networks(context.credentials, {:env=>context})
+    else
+      networks = context.driver.networks(context.credentials, {:id=>id, :env=>context})
+    end
+    networks
+  end
+
+  def self.create(request_body, context, type)
+    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false,"NormaliseSpace"=>2}) : JSON.parse(request_body)
+    if input["networkTemplate"]["href"] #template by reference
+      network_config, routing_group = get_by_reference(input, context)
+    else
+      if input["networkTemplate"]["networkConfig"]["href"] # configuration by reference
+        network_config = CIMI::Model::NetworkConfiguration.find(context.href_id(input["networkTemplate"]["networkConfig"]["href"],
+                                                                                :network_configurations), context)
+      else #configuration by value
+        network_config = get_by_value(request_body, type)
+      end
+      routing_group = CIMI::Model::RoutingGroup.find(context.href_id(input["networkTemplate"]["routingGroup"]["href"],
+                                                                     :routing_groups), context)
+    end
+    params = {:network_config => network_config, :routing_group => routing_group, :name=>input["name"],
+              :description=>input["description"], :env=>context}
+    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
+    context.driver.create_network(context.credentials, params)
+  end
+
+  def self.delete!(id, context)
+    context.driver.delete_network(context.credentials, id)
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_network", context.credentials, self.name)
+        block.callback :success
+      else
+        raise "Operation #{action.name} failed to execute on the Network #{self.name} "
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+  private
+
+  def self.get_by_reference(input, context)
+    network_template = CIMI::Model::NetworkTemplate.find(context.href_id(input["networkTemplate"]["href"], :network_templates), context)
+    network_config = CIMI::Model::NetworkConfiguration.find(context.href_id(network_template.network_config.href, :network_configurations), context)
+    routing_group = CIMI::Model::RoutingGroup.find(context.href_id(network_template.routing_group.href, :routing_groups), context)
+    return network_config, routing_group
+  end
+
+  def self.get_by_value(request_body, type)
+    if type == :xml
+      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
+      network_config = CIMI::Model::NetworkConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["networkTemplate"][0]["networkConfig"][0]))
+    else
+     json = JSON.parse(request_body)
+      network_config = CIMI::Model::NetworkConfiguration.from_json(JSON.generate(json["networkTemplate"]["networkConfig"]))
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/network_collection.rb b/server/lib/cimi/models/network_collection.rb
new file mode 100644
index 0000000..d76a3dd
--- /dev/null
+++ b/server/lib/cimi/models/network_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkCollection < CIMI::Model::Base
+
+  act_as_root_entity :network
+
+  array :networks do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.networks_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} NetworkCollection",
+      :networks => CIMI::Model::Network.all(context).map { |c| { :href => c.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/network_configuration.rb b/server/lib/cimi/models/network_configuration.rb
new file mode 100644
index 0000000..1b04548
--- /dev/null
+++ b/server/lib/cimi/models/network_configuration.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkConfiguration < CIMI::Model::Base
+
+  text :access
+
+  text :bandwidth_limit
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    network_configs = []
+    if id==:all
+      network_configs = context.driver.network_configurations(context.credentials, {:env=>context})
+    else
+      network_configs = context.driver.network_configurations(context.credentials, {:env=>context, :id=>id})
+    end
+    network_configs
+  end
+
+  def self.create_from_xml(request_body, context)
+  end
+
+  def self.create_from_json(request_body, context)
+  end
+end
diff --git a/server/lib/cimi/models/network_configuration_collection.rb b/server/lib/cimi/models/network_configuration_collection.rb
new file mode 100644
index 0000000..fc14592
--- /dev/null
+++ b/server/lib/cimi/models/network_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkConfigurationCollection < CIMI::Model::Base
+
+  act_as_root_entity :network_configuration
+
+  array :network_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.network_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} NetworkConfigurationCollection",
+      :network_configurations => CIMI::Model::NetworkConfiguration.all(context).map { |c| { :href => c.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/network_template.rb b/server/lib/cimi/models/network_template.rb
new file mode 100644
index 0000000..ce3b990
--- /dev/null
+++ b/server/lib/cimi/models/network_template.rb
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkTemplate < CIMI::Model::Base
+
+  href :network_config
+
+  href :routing_group
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    network_templates = []
+    if id==:all
+      network_templates = context.driver.network_templates(context.credentials, {:env=>context})
+    else
+      network_templates = context.driver.network_templates(context.credentials, {:env=>context, :id=>id})
+    end
+    network_templates
+  end
+
+end
diff --git a/server/lib/cimi/models/network_template_collection.rb b/server/lib/cimi/models/network_template_collection.rb
new file mode 100644
index 0000000..b2ac537
--- /dev/null
+++ b/server/lib/cimi/models/network_template_collection.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class CIMI::Model::NetworkTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :network_template
+
+  array :network_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.network_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} NetworkTemplateCollection",
+      :network_templates => CIMI::Model::NetworkTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group.rb b/server/lib/cimi/models/routing_group.rb
new file mode 100644
index 0000000..d26f4d7
--- /dev/null
+++ b/server/lib/cimi/models/routing_group.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::RoutingGroup < CIMI::Model::Base
+
+  array :networks do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.routing_groups(context.credentials, {:env=>context})
+    else
+      context.driver.routing_groups(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group_collection.rb b/server/lib/cimi/models/routing_group_collection.rb
new file mode 100644
index 0000000..285e164
--- /dev/null
+++ b/server/lib/cimi/models/routing_group_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::RoutingGroupCollection < CIMI::Model::Base
+
+  act_as_root_entity :routing_group
+
+  array :routing_groups do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.routing_groups_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} RoutingGroupCollection",
+      :routing_groups => CIMI::Model::RoutingGroup.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group_template.rb b/server/lib/cimi/models/routing_group_template.rb
new file mode 100644
index 0000000..204a353
--- /dev/null
+++ b/server/lib/cimi/models/routing_group_template.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::RoutingGroupTemplate < CIMI::Model::Base
+
+  array :networks do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.routing_group_templates(context.credentials, {:env=>context})
+    else
+      context.driver.routing_group_templates(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group_template_collection.rb b/server/lib/cimi/models/routing_group_template_collection.rb
new file mode 100644
index 0000000..61a4a68
--- /dev/null
+++ b/server/lib/cimi/models/routing_group_template_collection.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class CIMI::Model::RoutingGroupTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :routing_group_template
+
+  array :routing_group_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.routing_group_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} RoutingGroupTemplateCollection",
+      :routing_group_templates => CIMI::Model::RoutingGroupTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb
new file mode 100644
index 0000000..f301b69
--- /dev/null
+++ b/server/lib/cimi/models/schema.rb
@@ -0,0 +1,277 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+# The smarts of converting from XML and JSON into internal objects
+class CIMI::Model::Schema
+
+  #
+  # Attributes describe how we extract values from XML/JSON
+  #
+  class Attribute
+    attr_reader :name, :xml_name, :json_name
+
+    def initialize(name, opts = {})
+      @name = name
+      @xml_name = (opts[:xml_name] || name).to_s.camelize(true)
+      @json_name = (opts[:json_name] || name).to_s.camelize(true)
+    end
+
+    def from_xml(xml, model)
+      model[@name] = xml[@xml_name].first if xml.has_key?(@xml_name)
+    end
+
+    def from_json(json, model)
+      model[@name] = json[@json_name]
+    end
+
+    def to_xml(model, xml)
+      xml[@xml_name] = [model[@name]] if model[@name]
+    end
+
+    def to_json(model, json)
+      json[@json_name] = model[@name] if model and model[@name]
+    end
+  end
+
+  class Scalar < Attribute
+    def initialize(name, opts)
+      @text = opts[:text]
+      if ! [nil, :nested, :direct].include?(@text)
+        raise "text option for scalar must be :nested or :direct"
+      end
+      super(name, opts)
+    end
+
+    def text?; @text; end
+
+    def nested_text?; @text == :nested; end
+
+    def from_xml(xml, model)
+      case @text
+        when :nested then model[@name] = xml[@xml_name].first["content"] if xml[@xml_name]
+        when :direct then model[@name] = xml["content"]
+        else model[@name] = xml[@xml_name]
+      end
+    end
+
+    def to_xml(model, xml)
+      return unless model
+      return unless model[@name]
+      case @text
+        when :nested then xml[@xml_name] = [{ "content" => model[@name] }]
+        when :direct then xml["content"] = model[@name]
+        else xml[@xml_name] = model[@name]
+      end
+    end
+  end
+
+  class Struct < Attribute
+    def initialize(name, opts, &block)
+      content = opts[:content]
+      super(name, opts)
+      @schema = CIMI::Model::Schema.new
+      @schema.instance_eval(&block) if block_given?
+      @schema.scalar(content, :text => :direct) if content
+    end
+
+    def from_xml(xml, model)
+      xml = xml.has_key?(xml_name) ? xml[xml_name].first : {}
+      model[name] = convert_from_xml(xml)
+    end
+
+    def from_json(json, model)
+      json = json.has_key?(json_name) ? json[json_name] : {}
+      model[name] = convert_from_json(json)
+    end
+
+    def to_xml(model, xml)
+      conv = convert_to_xml(model[name])
+      xml[xml_name] = [conv] unless conv.empty?
+    end
+
+    def to_json(model, json)
+      conv = convert_to_json(model[name])
+      json[json_name] = conv unless conv.empty?
+    end
+
+    def convert_from_xml(xml)
+      sub = struct.new
+      @schema.from_xml(xml, sub)
+      sub
+    end
+
+    def convert_from_json(json)
+      sub = struct.new
+      @schema.from_json(json, sub)
+      sub
+    end
+
+    def convert_to_xml(model)
+      xml = {}
+      @schema.to_xml(model, xml)
+      xml
+    end
+
+    def convert_to_json(model)
+      json = {}
+      @schema.to_json(model, json)
+      json
+    end
+
+    private
+    def struct
+      cname = "CIMI_#{json_name.upcase_first}"
+      if ::Struct.const_defined?(cname)
+        ::Struct.const_get(cname)
+      else
+        ::Struct.new("CIMI_#{json_name.upcase_first}",
+                     *@schema.attribute_names)
+      end
+    end
+  end
+
+  class Array < Attribute
+    # For an array :things, we collect all <thing/> elements (XmlSimple
+    # actually does the collecting)
+    def initialize(name, opts = {}, &block)
+      opts[:xml_name] = name.to_s.singularize unless opts[:xml_name]
+      super(name, opts)
+      @struct = Struct.new(name, opts, &block)
+    end
+
+    def from_xml(xml, model)
+      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
+    end
+
+    def from_json(json, model)
+      model[name] = (json[json_name] || []).map { |elt| @struct.convert_from_json(elt) }
+    end
+
+    def to_xml(model, xml)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
+      xml[xml_name] = ary unless ary.empty?
+    end
+
+    def to_json(model, json)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
+      json[json_name] = ary unless ary.empty?
+    end
+  end
+
+  class Hash < Attribute
+
+    def initialize(name, opts = {}, &block)
+      opts[:json_name] = name.to_s.pluralize unless opts[:json_name]
+      super(name, opts)
+      @struct = Struct.new(name, opts, &block)
+    end
+
+    def from_xml(xml, model)
+      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
+    end
+
+    def from_json(json, model)
+      model[name] = (json[json_name] || {}).inject([]) do |result,item|
+        result << @struct.convert_from_json({ 'name' => item[0], 'value' => item[1] })
+      end
+    end
+
+    def to_xml(model, xml)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
+      xml[xml_name] = ary unless ary.empty?
+    end
+
+    def to_json(model, json)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
+      json[json_name] = ary.inject({}) { |result, item| result[item['name']] = item['value']; result } unless ary.empty?
+    end
+  end
+
+  #
+  # The actual Schema class
+  #
+  def initialize
+    @attributes = []
+  end
+
+  def from_xml(xml, model = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.from_xml(xml, model) }
+    model
+  end
+
+  def from_json(json, model = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.from_json(json, model) }
+    model
+  end
+
+  def to_xml(model, xml = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.to_xml(model, xml) }
+    xml
+  end
+
+  def to_json(model, json = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.to_json(model, json) }
+    json
+  end
+
+  def attribute_names
+    @attributes.map { |a| a.name }
+  end
+
+  #
+  # The DSL
+  #
+  # Requires that the class into which this is included has a
+  # +add_attributes!+ method
+  module DSL
+    def href(*args)
+      args.each { |arg| struct(arg) { scalar :href } }
+    end
+
+    def text(*args)
+      args.expand_opts!(:text => :nested)
+      scalar(*args)
+    end
+
+    def scalar(*args)
+      add_attributes!(args, Scalar)
+    end
+
+    def array(name, opts={}, &block)
+      add_attributes!([name, opts], Array, &block)
+    end
+
+    def struct(name, opts={}, &block)
+      add_attributes!([name, opts], Struct, &block)
+    end
+
+    def hash(name, opts={}, &block)
+      add_attributes!([name, opts], Hash, &block)
+    end
+  end
+
+  include DSL
+
+  def add_attributes!(args, attr_klass, &block)
+    raise "The schema has already been used to convert objects" if @attributes.frozen?
+    opts = args.extract_opts!
+    args.each { |arg| @attributes << attr_klass.new(arg, opts, &block) }
+  end
+end
diff --git a/server/lib/cimi/models/volume.rb b/server/lib/cimi/models/volume.rb
new file mode 100644
index 0000000..9c106e2
--- /dev/null
+++ b/server/lib/cimi/models/volume.rb
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Volume < CIMI::Model::Base
+
+  struct :capacity do
+    scalar :quantity
+    scalar :units
+  end
+  text :bootable
+  text :supports_snapshots
+  array :snapshots do
+    scalar :ref
+  end
+  text :guest_interface
+  array :meters do
+    scalar :ref
+  end
+  href :eventlog
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    volumes = []
+    opts = ( id == :all ) ? {} : { :id => id }
+    volumes = context.driver.storage_volumes(context.credentials, opts)
+    volumes.collect!{ |volume| from_storage_volume(volume, context) }
+    return volumes.first unless volumes.length > 1
+    return volumes
+  end
+
+  def self.all(context); find(:all, context); end
+
+  def self.create_from_json(json_in, context)
+    json = JSON.parse(json_in)
+    volume_config_id = json["volumeTemplate"]["volumeConfig"]["href"].split("/").last
+    volume_image_id = (json["volumeTemplate"].has_key?("volumeImage") ?
+                json["volumeTemplate"]["volumeImage"]["href"].split("/").last  : nil)
+    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
+  end
+
+  def self.create_from_xml(xml_in, context)
+    xml = XmlSimple.xml_in(xml_in)
+    volume_config_id = xml["volumeTemplate"][0]["volumeConfig"][0]["href"].split("/").last
+    volume_image_id = (xml["volumeTemplate"][0].has_key?("volumeImage") ?
+             xml["volumeTemplate"][0]["volumeImage"][0]["href"].split("/").last  : nil)
+    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_storage_volume(context.credentials, {:id=>id} )
+  end
+
+  def self.find_to_attach_from_json(json_in, context)
+    json = JSON.parse(json_in)
+    volumes = json["volumes"].map{|v| {:volume=>self.find(v["volume"]["href"].split("/volumes/").last, context),
+                                       :attachment_point=>v["attachmentPoint"]  }}
+  end
+
+  def self.find_to_attach_from_xml(xml_in, context)
+    xml = XmlSimple.xml_in(xml_in)
+    volumes = xml["volume"].map{|v| {:volume => self.find(v["href"].split("/volumes/").last, context),
+                                      :attachment_point=>v["attachmentPoint"] }}
+  end
+
+  private
+
+  def self.create_volume(params, context)
+    volume_config = CIMI::Model::VolumeConfiguration.find(params[:volume_config_id], context)
+    opts = {:capacity=>volume_config.capacity[:quantity], :snapshot_id=>params[:volume_image_id] }
+    storage_volume = self.driver.create_storage_volume(context.credentials, opts)
+    from_storage_volume(storage_volume, context)
+  end
+
+  def self.from_storage_volume(volume, context)
+    self.new( { :name => volume.id,
+                :description => volume.id,
+                :created => volume.created,
+                :id => context.volume_url(volume.id),
+                :capacity => { :quantity=>volume.capacity, :units=>"gibibyte"  }, #FIXME... units will vary
+                :bootable => "false", #fixme ... will vary... ec2 doesn't expose this
+                :supports_snapshots => "true", #fixme, will vary (true for ec2)
+                :snapshots => [], #fixme...
+                :guest_interface => "",
+                :eventlog => {:href=> "http://eventlogs"},#FIXME
+                :meters => []
+            } )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_collection.rb b/server/lib/cimi/models/volume_collection.rb
new file mode 100644
index 0000000..1f4152e
--- /dev/null
+++ b/server/lib/cimi/models/volume_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume
+
+  array :volumes do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volumes_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeCollection",
+      :volumes => CIMI::Model::Volume.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_configuration.rb b/server/lib/cimi/models/volume_configuration.rb
new file mode 100644
index 0000000..75b37ea
--- /dev/null
+++ b/server/lib/cimi/models/volume_configuration.rb
@@ -0,0 +1,60 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
+
+  text :format
+  struct :capacity do
+    scalar :quantity
+    scalar :units
+  end
+  text :supports_snapshots
+  text :guest_interface
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    volume_configs = []
+    if id == :all
+      #ec2 ebs volumes can 1gb..1tb
+      (1..1000).each do |size|
+        volume_configs << create(size, context)
+      end
+    else
+      volume_configs << create(id, context)
+      return volume_configs.first
+    end
+    return volume_configs
+  end
+
+
+  def self.all(context); find(:all, context); end
+
+  private
+
+  def self.create(size, context)
+    self.new( {
+                :id => context.volume_configuration_url(size),
+                :name => size,
+                :description => "volume configuration with #{size} GiB",
+                :created => Time.now.to_s,
+                :capacity => {:quantity=>size, :units=>"gibibytes"},
+                :supports_snapshots => "true"
+                # FIXME :guest_interface => "NFS"
+            } )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_configuration_collection.rb b/server/lib/cimi/models/volume_configuration_collection.rb
new file mode 100644
index 0000000..2120ae6
--- /dev/null
+++ b/server/lib/cimi/models/volume_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeConfigurationCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume_configuration
+
+  array :volume_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volume_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeConfigurationCollection",
+      :volume_configurations => CIMI::Model::VolumeConfiguration.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_image.rb b/server/lib/cimi/models/volume_image.rb
new file mode 100644
index 0000000..03cc7fd
--- /dev/null
+++ b/server/lib/cimi/models/volume_image.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeImage < CIMI::Model::Base
+
+  href :image_location
+  text :image_data
+  text :bootable
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    storage_snapshots = []
+    opts = ( id==:all  ) ? {}  : { :id=>id }
+    storage_snapshots = self.driver.storage_snapshots(context.credentials, opts)
+    storage_snapshots.collect!{ |snapshot| from_storage_snapshot(snapshot, context) }
+    return storage_snapshots.first unless storage_snapshots.length > 1
+    return storage_snapshots
+  end
+
+  def self.all(context); find(:all, context); end
+
+  private
+
+  def self.from_storage_snapshot(snapshot, context)
+    self.new( {
+               :name => snapshot.id,
+               :description => snapshot.id,
+               :created => snapshot.created,
+               :id => context.volume_image_url(snapshot.id),
+               :image_location => {:href=>context.volume_url(snapshot.storage_volume_id)},
+               :bootable => "false"  #FIXME
+            } )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_image_collection.rb b/server/lib/cimi/models/volume_image_collection.rb
new file mode 100644
index 0000000..f3da877
--- /dev/null
+++ b/server/lib/cimi/models/volume_image_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeImageCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume_image
+
+  array :volume_images do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volume_images_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeImageCollection",
+      :volume_images => CIMI::Model::VolumeImage.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_template.rb b/server/lib/cimi/models/volume_template.rb
new file mode 100644
index 0000000..b9c82db
--- /dev/null
+++ b/server/lib/cimi/models/volume_template.rb
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeTemplate < CIMI::Model::Base
+
+  href :volume_config
+  href :volume_image
+  array :operations do
+    scalar :rel, :href
+  end
+end
diff --git a/server/lib/cimi/models/volume_template_collection.rb b/server/lib/cimi/models/volume_template_collection.rb
new file mode 100644
index 0000000..f53547c
--- /dev/null
+++ b/server/lib/cimi/models/volume_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume_template
+
+  array :volume_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volume_template_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeTemplateCollection",
+      :volume_templates => CIMI::Model::VolumeTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp.rb b/server/lib/cimi/models/vsp.rb
new file mode 100644
index 0000000..b8b27f5
--- /dev/null
+++ b/server/lib/cimi/models/vsp.rb
@@ -0,0 +1,102 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSP < CIMI::Model::Base
+
+  text :state
+
+  href :network
+
+  text :bandwidth_reservation
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  href :event_log
+
+  array :meters do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.vsps(context.credentials, {:env=>context})
+    else
+      context.driver.vsps(context.credentials, {:id=>id, :env=>context})
+    end
+  end
+
+  def self.create(request_body, context, type)
+    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
+    if input["vspTemplate"]["href"] #template by reference
+      vsp_config, network = get_by_reference(input, context)
+    else
+      if input["vspTemplate"]["vspConfig"]["href"] # configuration by reference
+        vsp_config = CIMI::Model::VSPConfiguration.find(context.href_id(input["vspTemplate"]["vspConfig"]["href"],:vsp_configurations), context)
+      else #configuration by value
+        vsp_config = get_by_value(request_body, type)
+      end
+      network = CIMI::Model::Network.find(context.href_id(input["vspTemplate"]["network"]["href"], :networks), context)
+    end
+    params = {:vsp_config => vsp_config, :network => network, :name=>input["name"], :description=>input["description"], :env=>context}
+    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
+    context.driver.create_vsp(context.credentials, params)
+  end
+
+  def self.delete!(id, context)
+    context.driver.delete_vsp(context.credentials, id)
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_vsp", context.credentials, self.name)
+        block.callback :success
+      else
+        raise "Operation #{action.name} failed to execute on the VSP #{self.name} "
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+
+  private
+
+  def self.get_by_reference(input, context)
+    vsp_template = CIMI::Model::VSPTemplate.find(context.href_id(input["vspTemplate"]["href"], :vsp_templates), context)
+    vsp_config = CIMI::Model::VSPConfiguration.find(context.href_id(vsp_template.vsp_config.href, :vsp_configurations), context)
+    network = CIMI::Model::Network.find(context.href_id(vsp_template.network.href, :networks), context)
+    return vsp_config, network
+  end
+
+  def self.get_by_value(request_body, type)
+    if type == :xml
+      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
+      vsp_config = CIMI::Model::VSPConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["vspTemplate"][0]["vspConfig"][0]))
+    else
+     json = JSON.parse(request_body)
+      vsp_config = CIMI::Model::VSPConfiguration.from_json(JSON.generate(json["vspTemplate"]["vspConfig"]))
+    end
+  end
+end
diff --git a/server/lib/cimi/models/vsp_collection.rb b/server/lib/cimi/models/vsp_collection.rb
new file mode 100644
index 0000000..fc72024
--- /dev/null
+++ b/server/lib/cimi/models/vsp_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPCollection < CIMI::Model::Base
+
+  CIMI::Model.register_as_root_entity! "VSPs"
+
+  array :vsps do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.vsps_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VSPCollection",
+      :vsps => CIMI::Model::VSP.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_configuration.rb b/server/lib/cimi/models/vsp_configuration.rb
new file mode 100644
index 0000000..c9a9bf3
--- /dev/null
+++ b/server/lib/cimi/models/vsp_configuration.rb
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPConfiguration < CIMI::Model::Base
+
+  text :bandwidth_reservation
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.vsp_configurations(context.credentials, {:env=>context})
+    else
+      context.driver.vsp_configurations(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_configuration_collection.rb b/server/lib/cimi/models/vsp_configuration_collection.rb
new file mode 100644
index 0000000..d4927e7
--- /dev/null
+++ b/server/lib/cimi/models/vsp_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPConfigurationCollection < CIMI::Model::Base
+
+  CIMI::Model.register_as_root_entity! "VSPConfigurations"
+
+  array :vsp_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.vsp_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VSPConfigurationCollection",
+      :vsp_configurations => CIMI::Model::VSPConfiguration.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_template.rb b/server/lib/cimi/models/vsp_template.rb
new file mode 100644
index 0000000..f1b8078
--- /dev/null
+++ b/server/lib/cimi/models/vsp_template.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPTemplate < CIMI::Model::Base
+
+  href :network
+
+  href :vsp_config
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.vsp_templates(context.credentials, {:env=>context})
+    else
+      context.driver.vsp_templates(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_template_collection.rb b/server/lib/cimi/models/vsp_template_collection.rb
new file mode 100644
index 0000000..61d5311
--- /dev/null
+++ b/server/lib/cimi/models/vsp_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPTemplateCollection < CIMI::Model::Base
+
+  CIMI::Model.register_as_root_entity! "VSPTemplates"
+
+  array :vsp_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.vsp_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VSPTemplateCollection",
+      :vsp_templates => CIMI::Model::VSPTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
index 60f9a3b..a1c7ef9 100644
--- a/server/lib/cimi/server.rb
+++ b/server/lib/cimi/server.rb
@@ -13,947 +13,48 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'cimi/dependencies'
-require 'cimi/helpers/cimi_helper'
-require 'cimi/model'
+require 'rubygems'
+require 'crack'
+require 'json'
+require 'yaml'
+require 'haml'
+require 'sinatra/base'
+require 'sinatra/rabbit'
+require_relative '../sinatra'
 
-set :version, '0.1.0'
+require_relative './helpers'
+require_relative './collections'
 
-include Deltacloud::Drivers
-include CIMI::Model
+CMWG_NAMESPACE = "http://www.dmtf.org/cimi"
 
-set :drivers, Proc.new { driver_config }
+module CIMI
+  class API < Collections::Base
 
-Sinatra::Application.register Rack::RespondTo
+    # Enable logging
+    use Rack::CommonLogger
+    use Rack::Date
+    use Rack::ETag
+    use Rack::MatrixParams
+    use Rack::DriverSelect
+    use Rack::Accept
+    use Rack::MediaType
 
-use Rack::ETag
-use Rack::Runtime
-use Rack::MatrixParams
-use Rack::DriverSelect
-use Rack::MediaType
-use Rack::Date
-use Rack::CIMI
+    helpers CIMIHelper
 
-configure do
-  set :root_url, "/cimi"
-  set :views, File::join($top_srcdir, 'views', 'cimi')
-  set :public_folder, File::join($top_srcdir, 'public')
-  driver
-end
-
-configure :production do
-  use Rack::SyslogLogger
-  disable :logging
-  enable :show_errors
-  set :dump_errors, false
-  $stdout = SyslogFile.new
-  $stderr = $stdout
-end
-
-configure :development do
-  set :raise_errors => false
-  set :show_exceptions, false
-  $stdout.sync = true
-  $stderr.sync = true
-end
-
-# You could use $API_HOST environment variable to change your hostname to
-# whatever you want (eg. if you running API behind NAT)
-HOSTNAME=ENV['API_HOST'] ? ENV['API_HOST'] : nil
-
-error do
-  report_error
-end
-
-get "/" do
-  redirect settings.root_url
-end
-
-get "#{settings.root_url}\/?" do
-  halt 401 if params[:force_auth] and not driver.valid_credentials?(credentials)
-  redirect cloudEntryPoint_url, 301
-end
+    include Deltacloud::Helpers
+    include CIMI::Collections
+    include CIMI::Model
 
-global_collection  :cloudEntryPoint do
-  description 'Cloud entry point'
-  operation :index do
-    description "list all resources of the cloud"
-    control do
-      entry_point = CloudEntryPoint.create(self)
+    get API_ROOT_URL do
+      if params[:force_auth]
+        return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
+      end
+      entry_point = CIMI::Model::CloudEntryPoint.create(self)
       respond_to do |format|
         format.xml { entry_point.to_xml }
         format.json { entry_point.to_json }
       end
     end
-  end
-end
-
-global_collection :machine_configurations do
-  description 'List all machine configurations'
-
-  operation :index do
-    param :CIMISelect,  :string,  :optional
-    description "List all machine configurations"
-    control do
-      machine_configs = MachineConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machine_configs.to_xml }
-        format.json { machine_configs.to_json }
-      end
-    end
-  end
-
-  operation :show do
-
-    description "The Machine Configuration entity represents the set of configuration values "+
-      "that define the (virtual) hardware resources of a to-be-realized Machine Instance.."
-
-    param :id, :string, :required
-
-    control do
-      machine_conf = MachineConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine_conf.to_xml }
-        format.json { machine_conf.to_json }
-      end
-    end
-
-  end
-end
-
-global_collection :machine_images do
-  description 'List all machine images'
-
-  operation :index do
-    description "List all machine configurations"
-    param :CIMISelect,  :string,  :optional
-    control do
-      machine_images = MachineImageCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machine_images.to_xml }
-        format.json { machine_images.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific machine image."
-    param :id,          :string,    :required
-    control do
-      machine_image = MachineImage.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine_image.to_xml }
-        format.json { machine_image.to_json }
-      end
-    end
-  end
-
-end
-
-global_collection :machine_admins do
-  description 'Machine Admin entity'
-
-  operation :index do
-    description "List all machine admins"
-    param :CIMISelect,  :string,  :optional
-    with_capability :keys
-    control do
-      machine_admins = MachineAdminCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machine_admins.to_xml }
-        format.json { machine_admins.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific machine admin"
-    param :id,          :string,    :required
-    with_capability :key
-    control do
-      machine_admin = MachineAdmin.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine_admin.to_xml }
-        format.json { machine_admin.to_json }
-      end
-    end
-  end
-
-  operation :create do
-    description "Show specific machine admin"
-    with_capability :create_key
-    control do
-      if request.content_type.end_with?("+json")
-        new_admin = MachineAdmin.create_from_json(request.body.read, self)
-      else
-        new_admin = MachineAdmin.create_from_xml(request.body.read, self)
-      end
-      status 201 # Created
-      respond_to do |format|
-        format.json { new_admin.to_json }
-        format.xml { new_admin.to_xml }
-      end
-    end
-  end
-
-  operation :delete, :method => :delete, :member => true do
-    description "Delete specified MachineAdmin entity"
-    param :id,          :string,    :required
-    control do
-      MachineAdmin.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-end
-
-global_collection :machines do
-  description 'List all machine'
-
-  operation :index do
-    param :CIMISelect,  :string,  :optional
-    description "List all machines"
-    control do
-      machines = MachineCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machines.to_xml }
-        format.json { machines.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine.to_xml }
-        format.json { machine.to_json }
-      end
-    end
-  end
 
-  operation :create do
-    description "Create a new Machine entity."
-    control do
-      if request.content_type.end_with?("+json")
-        new_machine = Machine.create_from_json(request.body.read, self)
-      else
-        new_machine = Machine.create_from_xml(request.body.read, self)
-      end
-      status 201 # Created
-      respond_to do |format|
-        format.json { new_machine.to_json }
-        format.xml { new_machine.to_xml }
-      end
-    end
   end
-
-  operation :destroy do
-    description "Delete a specified machine."
-    param :id,          :string,    :required
-    control do
-      Machine.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      if request.content_type.end_with?("+json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      machine.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :restart, :method => :post, :member => true do
-    description "Start specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      if request.content_type.end_with?("+json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      machine.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      if request.content_type.end_with?("+json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      machine.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-#NOTE: The routes for attach/detach used here are NOT as specified by CIMI
-#will likely move later. CIMI specifies PUT of the whole Machine description
-#with inclusion/ommission of the volumes you want [att|det]ached
-  operation :attach_volume, :method => :put, :member => true do
-    description "Attach CIMI Volume(s) to a machine."
-    param :id, :string, :required
-    control do
-      if request.content_type.end_with?("+json")
-        volumes_to_attach = Volume.find_to_attach_from_json(request.body.read, self)
-      else
-        volumes_to_attach = Volume.find_to_attach_from_xml(request.body.read, self)
-      end
-      machine = Machine.attach_volumes(volumes_to_attach, self)
-      respond_to do |format|
-        format.json{ machine.to_json}
-        format.xml{machine.to_xml}
-      end
-    end
-  end
-
-  operation :detach_volume, :method => :put, :member => true do
-    description "Detach CIMI Volume(s) from a machine."
-    param :id, :string, :required
-    control do
-      if request.content_type.end_with?("+json")
-        volumes_to_detach = Volume.find_to_attach_from_json(request.body.read, self)
-      else
-        volumes_to_detach = Volume.find_to_attach_from_xml(request.body.read, self)
-      end
-      machine = Machine.detach_volumes(volumes_to_detach, self)
-      respond_to do |format|
-        format.json{ machine.to_json}
-        format.xml{machine.to_xml}
-      end
-    end
-  end
-end
-
-global_collection :volumes do
-  description "Volume represents storage at either the block or file-system level. Volumes can be attached to Machines. Once attached, Volumes can be accessed by processes on that Machine"
-
-  operation :index do
-    description "List all volumes"
-    param :CIMISelect,  :string,  :optional
-    control do
-      volumes = VolumeCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { volumes.to_xml }
-        format.json { volumes.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific Volume."
-    param :id, :string, :required
-    control do
-      volume = Volume.find(params[:id], self)
-      if volume
-        respond_to do |format|
-          format.xml  { volume.to_xml  }
-          format.json { volume.to_json }
-        end
-      else
-        report_error(404)
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new Volume."
-    control do
-      content_type = (request.content_type.end_with?("+json") ? :json  : :xml)
-          #((request.content_type.end_with?("+xml")) ? :xml : report_error(415) ) FIXME
-      case content_type
-        when :json
-          new_volume = Volume.create_from_json(request.body.read, self)
-        when :xml
-          new_volume = Volume.create_from_xml(request.body.read, self)
-      end
-      respond_to do |format|
-        format.json { new_volume.to_json }
-        format.xml { new_volume.to_xml }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified Volume"
-    param :id, :string, :required
-    control do
-      Volume.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-end
-
-global_collection :volume_configurations do
-  description "The Volume Configuration entity represents the set of configuration values needed to create a Volume with certain characteristics. Volume Configurations are created by Providers and MAY, at the Providers discretion, be created by Consumers"
-
-  operation :index do
-    description "Get list all VolumeConfigurations"
-    param :CIMISelect,  :string,  :optional
-    control do
-      volume_configuration = VolumeConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { volume_configuration.to_xml }
-        format.json { volume_configuration.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Get a specific VolumeConfiguration"
-    param :id, :required, :string
-    control do
-      volume_config = VolumeConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml { volume_config.to_xml }
-        format.json { volume_config.json }
-      end
-    end
-  end
-
-global_collection :volume_images do
-  description 'This entity represents an image that could be place on a pre-loaded volume.'
-
-  operation :index do
-    description "List all volumes images"
-    param :CIMISelect,  :string,  :optional
-    control do
-      volume_images = VolumeImageCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { volume_images.to_xml }
-        format.json { volume_images.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show a specific volume image"
-    param :id, :string, :required
-    control do
-      volume_image = VolumeImage.find(params[:id], self)
-      respond_to do |format|
-        format.xml { volume_image.to_xml }
-        format.json { volume_image.to_json }
-      end
-    end
-  end
-
-end
-
-
-global_collection :entity_metadata do
-  description 'This allows for the discovery of Provider defined constraints on the CIMI defined attributes as well as discovery of any new extension attributes that the Provider may have defined.'
-
-  operation :index do
-    description "List all entity metadata defined for this provider"
-    control do
-      entity_metadata = EntityMetadataCollection.default(self)
-      respond_to do |format|
-        format.xml{entity_metadata.to_xml}
-        format.json{entity_metadata.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description "Get the entity metadata for a specific collection"
-    param :id, :required, :string
-    control do
-      entity_metadata = EntityMetadata.find(params[:id], self)
-      respond_to do |format|
-        format.xml{entity_metadata.to_xml}
-        format.json{entity_metadata.to_json}
-      end
-    end
-  end
-
-end
-
-global_collection :networks do
-  description 'A Network represents an abstraction of a layer 2 broadcast domain'
-
-  operation :index do
-    description "List all Networks"
-    param :CIMISelect,  :string,  :optional
-    control do
-      networks = NetworkCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { networks.to_xml }
-        format.json { networks.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show a specific Network"
-    param :id, :string, :required
-    control do
-      network = Network.find(params[:id], self)
-      respond_to do |format|
-        format.xml { network.to_xml }
-        format.json { network.to_json }
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new Network"
-    control do
-      if request.content_type.end_with?("json")
-        network = Network.create(request.body.read, self, :json)
-      else
-        network = Network.create(request.body.read, self, :xml)
-      end
-      respond_to do |format|
-        format.xml { network.to_xml}
-        format.json { network.to_json }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified Network"
-    param :id, :string, :required
-    control do
-      Network.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start specific network."
-    param :id,          :string,    :required
-    control do
-      network = Network.find(params[:id], self)
-      report_error(404) unless network
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      network.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop specific network."
-    param :id,          :string,    :required
-    control do
-      network = Network.find(params[:id], self)
-      report_error(404) unless network
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      network.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :suspend, :method => :post, :member => true do
-    description "Suspend specific network."
-    param :id,          :string,    :required
-    control do
-      network = Network.find(params[:id], self)
-      report_error(404) unless network
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      network.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-end
-
-global_collection :network_configurations do
-  description 'Network Configurations contain the set of configuration values representing the information needed to create a Network with certain characteristics'
-
-  operation :index do
-    description 'List all NetworkConfigurations'
-    param :CIMISelect, :string, :optional
-    control do
-      network_configurations = NetworkConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { network_configurations.to_xml  }
-        format.json { network_configurations.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific NetworkConfiguration'
-    param :id, :string, :required
-    control do
-      network_config = NetworkConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml { network_config.to_xml }
-        format.json { network_config.to_json }
-      end
-    end
-  end
-end
-end
-
-global_collection :network_templates do
-
-  description 'Network Template is a set of configuration values for realizing a Network. An instance of Network Template may be used to create multiple Networks'
-
-  operation :index do
-    description 'List all Network Templates in the NetworkTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      network_templates = NetworkTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {network_templates.to_xml}
-        format.json {network_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific Network Template'
-    param :id, :string, :required
-    control do
-      network_template = NetworkTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {network_template.to_xml}
-        format.json {network_template.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :routing_groups do
-
-  description 'Routing Groups represent a collection of Networks that route to each other. Providers shall not allow two Networks to be routable to each other unless they are explicitly connected by being part of a common RoutingGroup.'
-
-  operation :index do
-    description 'List all RoutingGroups in the RoutingGroupsCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      routing_groups = RoutingGroupCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {routing_groups.to_xml}
-        format.json {routing_groups.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific RoutingGroup'
-    param :id, :string, :required
-    control do
-      routing_group = RoutingGroup.find(params[:id], self)
-      respond_to do |format|
-        format.xml {routing_group.to_xml}
-        format.json {routing_group.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :routing_group_templates do
-
-  description 'Routing Groups Templates capture the configuration values for realizing a RoutingGroup. A Routing Group Template may be used to create multiple RoutingGroups'
-
-  operation :index do
-    description 'List all RoutingGroupTemplates in the RoutingGroupTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      routing_group_templates = RoutingGroupTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {routing_group_templates.to_xml}
-        format.json {routing_group_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific RoutingGroupTemplate'
-    param :id, :string, :required
-    control do
-      routing_group_template = RoutingGroupTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {routing_group_template.to_xml}
-        format.json {routing_group_template.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :vsps do
-
-  description 'A VSP represents the connection parameters of a network port'
-
-  operation :index do
-    description 'List all VSPs in the VSPCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      vsps = VSPCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {vsps.to_xml}
-        format.json {vsps.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific VSP'
-    param :id, :string, :required
-    control do
-      vsp = VSP.find(params[:id], self)
-      respond_to do |format|
-        format.xml {vsp.to_xml}
-        format.json {vsp.to_json}
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new VSP"
-    control do
-      if request.content_type.end_with?("json")
-        vsp = CIMI::Model::VSP.create(request.body.read, self, :json)
-      else
-        vsp = CIMI::Model::VSP.create(request.body.read, self, :xml)
-      end
-      respond_to do |format|
-        format.xml { vsp.to_xml }
-        format.json { vsp.to_json }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified VSP"
-    param :id, :string, :required
-    control do
-      CIMI::Model::VSP.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start specific VSP."
-    param :id,          :string,    :required
-    control do
-      vsp = VSP.find(params[:id], self)
-      report_error(404) unless vsp
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      vsp.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop specific VSP."
-    param :id,          :string,    :required
-    control do
-      vsp = VSP.find(params[:id], self)
-      report_error(404) unless vsp
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      vsp.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-end
-
-global_collection :vsp_configurations do
-
-  description 'A VSP Configuration is the set of configuration values representing the information needed to create a VSP with certain characteristics'
-
-  operation :index do
-    description 'List all VSPConfigurations in the VSPConfigurationCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      vsp_configs = VSPConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {vsp_configs.to_xml}
-        format.json {vsp_configs.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific VSPConfiguration'
-    param :id, :string, :required
-    control do
-      vsp_config = VSPConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml {vsp_config.to_xml}
-        format.json {vsp_config.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :vsp_templates do
-
-  description 'The VSP Template is a set of Configuration values for realizing a VSP. A VSP Template may be used to create multiple VSPs'
-
-  operation :index do
-    description 'List all VSPTemplates in the VSPTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      vsp_templates = VSPTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {vsp_templates.to_xml}
-        format.json {vsp_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific VSPTemplate'
-    param :id, :string, :required
-    control do
-      vsp_template = VSPTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {vsp_template.to_xml}
-        format.json {vsp_template.to_json}
-      end
-    end
-  end
-
-end
-
-global_collection :addresses do
-
-  description 'An Address represents an IP address, and its associated metdata, for a particular Network.'
-
-  operation :index do
-    description 'List all Addresses in the AddressCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      addresses = AddressCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {addresses.to_xml}
-        format.json {addresses.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific Address'
-    param :id, :string, :required
-    control do
-      address = CIMI::Model::Address.find(params[:id], self)
-      respond_to do |format|
-        format.xml {address.to_xml}
-        format.json {address.to_json}
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new Address"
-    control do
-      if request.content_type.end_with?("json")
-        address = CIMI::Model::Address.create(request.body.read, self, :json)
-      else
-        address = CIMI::Model::Address.create(request.body.read, self, :xml)
-      end
-      respond_to do |format|
-        format.xml { address.to_xml }
-        format.json { address.to_json }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified Address"
-    param :id, :string, :required
-    control do
-      CIMI::Model::Address.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-end
-
-
-global_collection :address_templates do
-
-  description 'An AddressTemplate captures the configuration values for realizing an Address. An Address Template may be used to create multiple Addresses.'
-
-  operation :index do
-    description 'List all AddressTemplates in the AddressTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      address_templates = AddressTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {address_templates.to_xml}
-        format.json {address_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific AddressTemplate'
-    param :id, :string, :required
-    control do
-      address_template = CIMI::Model::AddressTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {address_template.to_xml}
-        format.json {address_template.to_json}
-      end
-    end
-  end
-
 end
-- 
1.7.10.1


[PATCH core 13/51] Core: CIMI helper is now not longer registred using Sinatra::Application

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/helpers/cimi_helper.rb |    2 --
 1 file changed, 2 deletions(-)

diff --git a/server/lib/cimi/helpers/cimi_helper.rb b/server/lib/cimi/helpers/cimi_helper.rb
index b3f3493..e48fa8e 100644
--- a/server/lib/cimi/helpers/cimi_helper.rb
+++ b/server/lib/cimi/helpers/cimi_helper.rb
@@ -28,8 +28,6 @@ module CIMIHelper
 
 end
 
-helpers CIMIHelper
-
 class Array
   def to_xml_cimi_collection(_self)
     model_name = first.class.xml_tag_name
-- 
1.7.10.1


[PATCH core 03/51] Core: Replaced obsolete or unused Deltacloud code

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/backend_capability.rb        |   42 --
 server/lib/deltacloud/base_driver.rb               |   18 -
 server/lib/deltacloud/base_driver/mock_driver.rb   |   78 ----
 server/lib/deltacloud/collections/instances.rb     |    3 +
 server/lib/deltacloud/core_ext.rb                  |   21 -
 .../lib/deltacloud/drivers/ec2/ec2_mock_driver.rb  |  186 ---------
 server/lib/deltacloud/hardware_profile.rb          |  192 ---------
 server/lib/deltacloud/helpers.rb                   |    2 -
 .../lib/deltacloud/helpers/application_helper.rb   |  238 -----------
 server/lib/deltacloud/helpers/auth_helper.rb       |   73 ++++
 server/lib/deltacloud/helpers/blob_stream.rb       |  213 ----------
 .../lib/deltacloud/helpers/blob_stream_helper.rb   |  214 ++++++++++
 server/lib/deltacloud/helpers/conversion_helper.rb |   43 --
 server/lib/deltacloud/helpers/deltacloud_helper.rb |  273 ++++++++++++
 server/lib/deltacloud/helpers/driver_helper.rb     |   57 +++
 .../deltacloud/helpers/hardware_profiles_helper.rb |   62 ---
 server/lib/deltacloud/helpers/json_helper.rb       |   31 --
 server/lib/deltacloud/helpers/rabbit_helper.rb     |   34 ++
 server/lib/deltacloud/helpers/url_helper.rb        |  112 +++++
 server/lib/deltacloud/method_serializer.rb         |   83 ----
 server/lib/deltacloud/models/instance.rb           |    2 -
 server/lib/deltacloud/models/key.rb                |    4 +
 server/lib/deltacloud/validation.rb                |  100 -----
 server/lib/sinatra/lazy_auth.rb                    |   75 ----
 server/lib/sinatra/rabbit.rb                       |  441 --------------------
 server/lib/sinatra/rack_accept.rb                  |    4 -
 server/lib/sinatra/rack_cimi.rb                    |   33 --
 server/lib/sinatra/rack_matrix_params.rb           |    4 +-
 server/lib/sinatra/rack_runtime.rb                 |   47 ---
 server/lib/sinatra/rack_syslog.rb                  |   93 -----
 server/lib/sinatra/sinatra_verbose.rb              |   73 ----
 server/lib/sinatra/static_assets.rb                |   99 -----
 server/lib/sinatra/url_for.rb                      |   93 -----
 server/views/addresses/show.html.haml              |    2 +-
 server/views/api/show.html.haml                    |    7 +-
 server/views/error.html.haml                       |    4 +-
 server/views/instances/new.html.haml               |   12 +-
 server/views/instances/show.xml.haml               |    2 +-
 server/views/layout.html.haml                      |    6 +-
 server/views/root/index.html.haml                  |    2 +-
 40 files changed, 789 insertions(+), 2289 deletions(-)
 delete mode 100644 server/lib/deltacloud/backend_capability.rb
 delete mode 100644 server/lib/deltacloud/base_driver.rb
 delete mode 100644 server/lib/deltacloud/base_driver/mock_driver.rb
 delete mode 100644 server/lib/deltacloud/core_ext.rb
 delete mode 100644 server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb
 delete mode 100644 server/lib/deltacloud/hardware_profile.rb
 delete mode 100644 server/lib/deltacloud/helpers/application_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/auth_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/blob_stream.rb
 create mode 100644 server/lib/deltacloud/helpers/blob_stream_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/conversion_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/deltacloud_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/driver_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/hardware_profiles_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/json_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/rabbit_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/url_helper.rb
 delete mode 100644 server/lib/deltacloud/method_serializer.rb
 delete mode 100644 server/lib/deltacloud/validation.rb
 delete mode 100644 server/lib/sinatra/lazy_auth.rb
 delete mode 100644 server/lib/sinatra/rabbit.rb
 delete mode 100644 server/lib/sinatra/rack_cimi.rb
 delete mode 100644 server/lib/sinatra/rack_runtime.rb
 delete mode 100644 server/lib/sinatra/rack_syslog.rb
 delete mode 100644 server/lib/sinatra/sinatra_verbose.rb
 delete mode 100644 server/lib/sinatra/static_assets.rb
 delete mode 100644 server/lib/sinatra/url_for.rb

diff --git a/server/lib/deltacloud/backend_capability.rb b/server/lib/deltacloud/backend_capability.rb
deleted file mode 100644
index 7f19007..0000000
--- a/server/lib/deltacloud/backend_capability.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud::BackendCapability
-
-  attr_reader :capability
-
-  def with_capability(capability)
-    @capability = capability
-  end
-
-  def has_capability?(backend)
-    !capability or backend.has_capability?(capability)
-  end
-
-  def check_capability(backend)
-    if !has_capability?(backend)
-      raise Deltacloud::ExceptionHandler::NotSupported.new("#{capability} capability not supported by backend #{backend.class.name}")
-    end
-  end
-
-  module Helpers
-    def operations_for_collection(collection)
-      collections[collection].operations.values.select { |op| op.has_capability?(driver) }
-    end
-  end
-
-  helpers Helpers
-end
diff --git a/server/lib/deltacloud/base_driver.rb b/server/lib/deltacloud/base_driver.rb
deleted file mode 100644
index 77cdc84..0000000
--- a/server/lib/deltacloud/base_driver.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/base_driver/base_driver'
-require 'deltacloud/base_driver/features'
diff --git a/server/lib/deltacloud/base_driver/mock_driver.rb b/server/lib/deltacloud/base_driver/mock_driver.rb
deleted file mode 100644
index 7956281..0000000
--- a/server/lib/deltacloud/base_driver/mock_driver.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/method_serializer'
-
-# Create 'mock' version of original driver client/gem:
-
-# Initialize driver and include Deltacloud
-include Deltacloud
-driver
-
-module Mock
-
-  class Ec2 < Aws::Ec2
-
-    include MethodSerializer::Cache
-
-    def self.cached_methods
-      [
-        :describe_images,
-        :describe_images_by_owner,
-        :describe_availability_zones,
-        :launch_instances,
-        :describe_instances,
-        :reboot_instances,
-        :create_tag,
-        :delete_tag,
-        :describe_tags,
-        :terminate_instances,
-        :describe_key_pairs,
-        :create_key_pair,
-        :delete_key_pair,
-        :create_volume,
-        :get_console_output,
-        :describe_volumes,
-        :delete_volume,
-        :attach_volume,
-        :detach_volume,
-        :describe_snapshots,
-        :associate_address,
-        :try_create_snapshot,
-      ]
-    end
-
-    MethodSerializer::Cache::wrap_methods(self, :cache_dir => File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'tests', 'ec2', 'support'))
-  end
-
-end
-
-
-# Replace original client with mock client
-Deltacloud::Drivers::EC2::EC2Driver.class_eval do
-  alias_method :original_new_client, :new_client
-
-  def new_client(credentials, provider = :ec2)
-    auth_credentials = { :access_key_id => credentials.user, :secret_access_key => credentials.password}
-    if provider == :elb
-      Mock::ELB.new(auth_credentials)
-    elsif provider == :s3
-      Mock::S3.new(auth_credentials)
-    else
-      Mock::Ec2.new(auth_credentials[:access_key_id], auth_credentials[:secret_access_key])
-    end
-  end
-
-end
diff --git a/server/lib/deltacloud/collections/instances.rb b/server/lib/deltacloud/collections/instances.rb
index 5202149..0da94f2 100644
--- a/server/lib/deltacloud/collections/instances.rb
+++ b/server/lib/deltacloud/collections/instances.rb
@@ -27,6 +27,9 @@ module Deltacloud::Collections
       @hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
       @realms = [Realm.new(:id => params[:realm_id])] if params[:realm_id]
       @realms ||= driver.realms(credentials)
+      if driver.class.has_feature? :instances, :authentication_key
+        @keys = driver.keys(credentials)
+      end
     end
 
     collection :instances do
diff --git a/server/lib/deltacloud/core_ext.rb b/server/lib/deltacloud/core_ext.rb
deleted file mode 100644
index fedbc18..0000000
--- a/server/lib/deltacloud/core_ext.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/core_ext/string'
-require 'deltacloud/core_ext/integer'
-require 'deltacloud/core_ext/hash'
-require 'deltacloud/core_ext/array'
-require 'deltacloud/core_ext/proc'
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb
deleted file mode 100644
index 03db2c1..0000000
--- a/server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb
+++ /dev/null
@@ -1,186 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module RightAws
-  class MockEc2
-
-    def initialize(opts={})
-    end
-
-    def describe_images(id)
-      load_fixtures_for(:images).select { |i| i[:aws_id].eql?(id) }
-    end
-
-    def describe_images_by_owner(id)
-      load_fixtures_for(:images).select { |i| i[:aws_owner].eql?(id) }
-    end
-
-    def describe_images(opts={})
-      load_fixtures_for(:images)
-    end
-
-    def describe_availability_zones(opts={})
-      load_fixtures_for(:realms)
-    end
-
-    def describe_instances(opts={})
-      instances = load_fixtures_for(:instances)
-      instances.each_with_index do |instance, i|
-        instances[i] = update_delayed_state(instance)
-        return [instance] if opts and opts[:id] and instance[:aws_instance_id].eql?(opts[:id])
-      end
-      update_fixtures_for(:instances, instances)
-      instances
-    end
-
-    def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='', addressing_type = nil, instance_type = nil, kernel_id = nil, ramdisk_id = nil, availability_zone = nil, block_device_mappings = nil)
-
-      instances = load_fixtures_for(:instances)
-      image = load_fixtures_for(:images).select { |img| img[:aws_id].eql?(image_id) }.first
-
-      if availability_zone
-        realm = load_fixtures_for(:realms).select { |realm| realm[:zone_name].eql?(availability_zone) }.first
-      else
-        realm = load_fixtures_for(:realms).first
-      end
-
-      raise Exception unless image
-      raise Exception unless realm
-
-      instance = { }
-      instance[:aws_image_id] = image[:aws_id]
-      instance[:aws_availability_zone] = realm[:zone_name]
-      instance[:aws_instance_type] = instance_type
-      instance[:aws_owner] = user_data
-      instance[:aws_state] = 'pending'
-      instance[:aws_reason] = ''
-      instance[:dns_name] = "#{random_dns}-01-C9.usma2.compute.amazonaws.com"
-      instance[:private_dns_name] = "#{random_dns}-02-P9.usma2.compute.amazonaws.com"
-      instance[:aws_state_code] = "0"
-      instance[:aws_key_name] = "staging"
-      instance[:aws_kernel_id] = "aki-be3adfd7"
-      instance[:aws_ramdisk_id] = "ari-ce34gad7"
-      instance[:aws_groups] = ["default"]
-      instance[:aws_instance_id] = random_instance_id
-      instance[:aws_reservation_id] = "r-aabbccdd"
-      instance[:aws_launch_time] = instance_time_format
-
-      instances << instance
-
-      update_fixtures_for(:instances, instances)
-
-      return [instance]
-    end
-
-
-    def terminate_instances(id)
-      update_instance_state(id, 'stopping', '80')
-    end
-
-    def reboot_instances(id)
-      update_instance_state(id, 'pending', '0')
-    end
-
-    alias :destroy_instance :terminate_instances
-
-    def describe_snapshots(opts={})
-      load_fixtures_for(:storage_snapshot)
-    end
-
-    def describe_volumes(opts={})
-      load_fixtures_for(:storage_volume)
-    end
-
-    private
-
-    def driver_dir
-      File::expand_path(File::join(File::dirname(__FILE__), '../../../../features/support/ec2'))
-    end
-
-    def fixtures_path
-      File::expand_path(File::join(driver_dir, 'fixtures'))
-    end
-
-    def load_fixtures_for(collection)
-      YAML.load_file(File::join(fixtures_path, "#{collection}.yaml"))
-    end
-
-    def update_fixtures_for(collection, new_data)
-      File.open(File::join(fixtures_path, "#{collection}.yaml"), 'w' ) do |out|
-        YAML.dump(new_data, out)
-      end
-      return new_data
-    end
-
-    def instance_time_format
-      DateTime.now.to_s.gsub(/\+(.+)$/, '.000Z')
-    end
-
-    def random_instance_id
-      id_1 = ("%.4s" % Time.now.to_i.to_s.reverse).reverse
-      id_2 = ("%.3s" % Time.now.to_i.to_s.reverse)
-      "i-#{id_1}f#{id_2}"
-    end
-
-    def random_dns
-      "domU-#{rand(90)+10}-#{rand(90)+10}-#{rand(90)+10}-#{rand(90)+10}"
-    end
-
-    def update_delayed_state(instance)
-      time = DateTime.now - DateTime.parse(instance[:aws_launch_time])
-      hours, minutes, seconds, frac = Date.day_fraction_to_time(time)
-
-      if (minutes>(rand(2)+1) or hours>0) and instance[:aws_state].eql?('pending')
-        instance[:aws_state], instance[:aws_state_code] = 'running', '16'
-      end
-
-      if (minutes>(rand(1)+1) or hours>0) and instance[:aws_state].eql?('stopping')
-        instance[:aws_state], instance[:aws_state_code] = 'stopped', '80'
-      end
-
-      return instance
-    end
-
-    def update_instance_state(id, state, state_code)
-      instance = describe_instances(:id => id).first
-      if instance
-        instance[:aws_state], instance[:aws_state_code] = state, state_code
-        instance[:aws_launch_time] = instance_time_format
-        instances = load_fixtures_for(:instances)
-        instances.each_with_index do |inst, i|
-          instances[i] = instance if inst[:aws_instance_id].eql?(id)
-        end
-        update_fixtures_for(:instances, instances)
-        return instance
-      else
-        raise Exception
-      end
-    end
-
-  end
-end
-
-Deltacloud::Drivers::EC2::EC2Driver.class_eval do
-  alias_method :original_new_client, :new_client
-
-  def new_client(credentials, opts={})
-    if credentials.user != 'mockuser' and credentials.password != 'mockpassword'
-      raise "AuthFailure"
-    end
-    RightAws::MockEc2.new
-  end
-
-end
diff --git a/server/lib/deltacloud/hardware_profile.rb b/server/lib/deltacloud/hardware_profile.rb
deleted file mode 100644
index 162f7af..0000000
--- a/server/lib/deltacloud/hardware_profile.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud
-  class HardwareProfile
-
-    UNITS = {
-      :memory => "MB",
-      :storage => "GB",
-      :architecture => "label",
-      :cpu => "count"
-    }
-
-    def self.unit(name)
-      UNITS[name]
-    end
-
-    class Property
-      attr_reader :name, :kind, :default
-      # kind == :range
-      attr_reader :first, :last
-      # kind == :enum
-      attr_reader :values
-      # kind == :fixed
-      attr_reader :value
-
-      def initialize(name, values, opts = {})
-        @name = name
-        if values.is_a?(Range)
-          @kind = :range
-          @first = values.first
-          @last = values.last
-          @default = values.first
-        elsif values.is_a?(Array)
-          @kind = :enum
-          @values = values
-          @default = values.first
-        else
-          @kind = :fixed
-          @value = values
-          @default = @value
-        end
-        @default = opts[:default] if opts[:default]
-      end
-
-      def unit
-        HardwareProfile.unit(name)
-      end
-
-      def param
-        :"hwp_#{name}"
-      end
-
-      def fixed?
-        kind == :fixed
-      end
-
-      def valid?(v)
-        v = convert_property_value_type(v)
-        case kind
-          # NOTE:
-          # Currently we cannot validate fixed values because of UI
-          # limitation. In UI we have multiple hwp_* properties which overide
-          # each other.
-          # Then provider have one 'static' hardware profile and one
-          # 'customizable' when user select the static one the UI also send
-          # values from the customizable one (which will lead to a validation
-          # error because validation algorith will think that client want to
-          # overide fixed values.
-          #
-          # when :fixed then (v == @default.to_s)
-          when :fixed then true
-          when :range then match_type?(first, v) and (first..last).include?(v)
-          when :enum then match_type?(values.first, v) and values.include?(v)
-          else false
-        end
-      end
-
-      def to_param
-        Validation::Param.new([param, :string, :optional, []])
-      end
-
-      def include?(v)
-        if kind == :fixed
-          return v == value
-        else
-          return values.include?(v)
-        end
-      end
-
-      private
-
-      def match_type?(reference, value)
-        true if reference.class == value.class
-      end
-
-      def convert_property_value_type(v)
-        return v.to_f if v =~ /(\d+)\.(\d+)/
-        return v.to_i if v =~ /(\d+)/
-        v.to_s
-      end
-    end
-
-    class << self
-      def property(prop)
-        define_method(prop) do |*args|
-          values, opts, *ignored = *args
-          instvar = :"@#{prop}"
-          unless values.nil?
-            @properties[prop] = Property.new(prop, values, opts || {})
-          end
-          @properties[prop]
-        end
-      end
-    end
-
-    attr_reader :name
-    property :cpu
-    property :architecture
-    property :memory
-    property :storage
-
-    def initialize(name,&block)
-      @properties   = {}
-      @name         = name
-      instance_eval &block if block_given?
-    end
-
-    def each_property(&block)
-      @properties.each_value { |prop| yield prop }
-    end
-
-    def properties
-      @properties.values
-    end
-
-    def property(name)
-      @properties[name.to_sym]
-    end
-
-    def default?(prop, v)
-      p = @properties[prop.to_sym]
-      p && p.default.to_s == v
-    end
-
-    def to_hash
-      props = []
-      self.each_property do |p|
-        if p.kind.eql? :fixed
-          props << { :kind => p.kind, :value => p.value, :name => p.name, :unit => p.unit }
-        else
-          param = { :operation => "create", :method => "post", :name => p.name }
-          if p.kind.eql? :range
-            param[:range] = { :first => p.first, :last => p.last }
-          elsif p.kind.eql? :enum
-            param[:enum] = p.values.collect { |v| { :entry => v } }
-          end
-          param
-          props << { :kind => p.kind, :value => p.default, :name => p.name, :unit => p.unit, :param => param }
-        end
-      end
-      {
-        :id => self.name,
-        :properties => props
-      }
-    end
-
-    def include?(prop, v)
-      p = @properties[prop]
-      p.nil? || p.include?(v)
-    end
-
-    def params
-      @properties.values.inject([]) { |m, prop|
-        m << prop.to_param
-      }.compact
-    end
-  end
-end
diff --git a/server/lib/deltacloud/helpers.rb b/server/lib/deltacloud/helpers.rb
index 73f79ec..dc382bd 100644
--- a/server/lib/deltacloud/helpers.rb
+++ b/server/lib/deltacloud/helpers.rb
@@ -17,7 +17,6 @@
 require_relative 'helpers/driver_helper'
 require_relative 'helpers/auth_helper'
 require_relative 'helpers/url_helper'
-require_relative 'helpers/assets_helper'
 require_relative 'helpers/deltacloud_helper'
 require_relative 'helpers/rabbit_helper'
 require_relative 'helpers/blob_stream_helper'
@@ -36,7 +35,6 @@ module Deltacloud::Collections
     helpers Deltacloud::Helpers::Drivers
     helpers Sinatra::AuthHelper
     helpers Sinatra::UrlForHelper
-    helpers Sinatra::StaticAssets::Helpers
     helpers Rack::RespondTo::Helpers
     helpers Deltacloud::Helpers::Application
 
diff --git a/server/lib/deltacloud/helpers/application_helper.rb b/server/lib/deltacloud/helpers/application_helper.rb
deleted file mode 100644
index 7a0d58b..0000000
--- a/server/lib/deltacloud/helpers/application_helper.rb
+++ /dev/null
@@ -1,238 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-# Methods added to this helper will be available to all templates in the application.
-
-require 'benchmark'
-
-module ApplicationHelper
-
-  include Deltacloud
-
-  def instance_action_method(action)
-    action_method(action, :instances)
-  end
-
-  def action_method(action, collection)
-    collections[collection].operations[action.to_sym].method
-  end
-
-  def driver_has_feature?(feature_name, collection_name = :instances)
-    driver.features(collection_name).any? { |f| f.name == feature_name }
-  end
-
-  def driver_has_auth_features?
-    driver_has_feature?(:authentication_password) || driver_has_feature?(:authentication_key)
-  end
-
-  def driver_auth_feature_name
-    'key' if driver_has_feature?(:authentication_key)
-    'password' if driver_has_feature?(:authentication_password)
-  end
-
-  def filter_all(model)
-      filter = {}
-      filter.merge!(:id => params[:id]) if params[:id]
-      filter.merge!(:architecture => params[:architecture]) if params[:architecture]
-      filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
-      filter.merge!(:state => params[:state]) if params[:state]
-      filter = {} if filter.keys.size.eql?(0)
-      singular = model.to_s.singularize.to_sym
-      begin
-       @benchmark = Benchmark.measure do
-          @elements = driver.send(model.to_sym, credentials, filter)
-        end
-      rescue
-        @exception = $!
-      end
-      if @elements
-        headers['X-Backend-Runtime'] = @benchmark.real.to_s
-        instance_variable_set(:"@#{model}", @elements)
-        respond_to do |format|
-          format.html { haml :"#{model}/index" }
-          format.xml { haml :"#{model}/index" }
-          format.json { convert_to_json(singular, @elements) }
-        end
-      else
-        report_error(@exception.code)
-      end
-  end
-
-  def show(model)
-    @benchmark = Benchmark.measure do
-      @element = driver.send(model, credentials, { :id => params[:id]} )
-    end
-    headers['X-Backend-Runtime'] = @benchmark.real.to_s
-    instance_variable_set("@#{model}", @element)
-    if @element
-      respond_to do |format|
-        format.html { haml :"#{model.to_s.pluralize}/show" }
-        format.xml { haml :"#{model.to_s.pluralize}/show" }
-        format.json { convert_to_json(model, @element) }
-      end
-    else
-      report_error(404)
-    end
-  end
-
-  def report_error(code=nil)
-    @error, @code = (request.env['sinatra.error'] || @exception), code
-    @code = 500 if not @code and not @error.class.method_defined? :code
-    response.status = @code || @error.code
-    respond_to do |format|
-      format.xml {  haml :"errors/#{@code || @error.code}", :layout => false }
-      format.json { json_return_error(@error) }
-      format.html { haml :"errors/#{@code || @error.code}", :layout => :error }
-    end
-  end
-
-  def instance_action(name)
-    original_instance = driver.instance(credentials, :id => params[:id])
-
-    # If original instance doesn't include called action
-    # return with 405 error (Method is not Allowed)
-    unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
-      return report_error(405)
-    end
-
-    @benchmark = Benchmark.measure do
-      @instance = driver.send(:"#{name}_instance", credentials, params[:id])
-    end
-
-    headers['X-Backend-Runtime'] = @benchmark.real.to_s
-
-    if name == :reboot
-      status 202
-    end
-
-    if name == :destroy
-      respond_to do |format|
-        format.xml { return 204 }
-        format.json { return 204 }
-        format.html { return redirect(instances_url) }
-      end
-    end
-
-    if @instance.class != Instance
-      response['Location'] = instance_url(params[:id])
-      halt
-    end
-
-    respond_to do |format|
-      format.xml { haml :"instances/show" }
-      format.html { haml :"instances/show" }
-      format.json {convert_to_json(:instance, @instance) }
-    end
-  end
-
-  def cdata(text = nil, &block)
-    text ||= capture_haml(&block)
-    "<![CDATA[#{text.strip}]]>"
-  end
-
-  def render_cdata(text)
-    "<![CDATA[#{text.strip}]]>"
-  end
-
-  def link_to_action(action, url, method)
-    capture_haml do
-      haml_tag :form, :method => :post, :action => url, :class => [:link, method], :'data-ajax' => 'false' do
-        haml_tag :input, :type => :hidden, :name => '_method', :value => method
-        haml_tag :button, :type => :submit, :'data-ajax' => 'false', :'data-inline' => "true" do
-          haml_concat action
-        end
-      end
-    end
-  end
-
-  def link_to_format(format)
-    return unless request.env['REQUEST_URI']
-    uri = request.env['REQUEST_URI']
-    return if uri.include?('format=')
-    uri += uri.include?('?') ? "&format=#{format}" : "?format=#{format}"
-    capture_haml do
-      haml_tag :a, :href => uri, :'data-ajax' => 'false', :'data-icon' => 'grid' do
-        haml_concat format.to_s.upcase
-      end
-    end
-  end
-
-  def image_for_state(state)
-    state_img = "stopped" if (state!='RUNNING' or state!='PENDING')
-    capture_haml do
-      haml_tag :img, :src => "/images/#{state}" % state.downcase, :title => state
-    end
-  end
-
-  # Reverse the entrypoints hash for a driver from drivers.yaml; note that
-  # +d+ is a hash, not an actual driver object
-  def driver_provider(d)
-    result = {}
-    if d[:entrypoints]
-      d[:entrypoints].each do |kind, details|
-        details.each do |prov, url|
-          result[prov] ||= {}
-          result[prov][kind] = url
-        end
-      end
-    end
-    result
-  end
-
-  def header(title, opts={}, &block)
-    opts[:theme] ||= 'b'
-    opts[:back] ||= 'true'
-    capture_haml do
-      haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme], :'data-add-back-btn' => opts[:back] do
-        haml_tag :a, :'data-rel' => :back do
-          haml_concat "Back"
-        end if opts[:back] == 'true'
-        haml_tag :h1 do
-          haml_concat title
-        end
-        block.call if block_given?
-      end
-    end
-  end
-
-  def subheader(title, opts={})
-    opts[:theme] ||= 'a'
-    capture_haml do
-      haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme] do
-        haml_tag :p, :class => 'inner-right' do
-          haml_concat title
-        end
-      end
-    end
-  end
-
-  def translate_error_code(code)
-    case code
-      when 400; { :message => "Bad Request" }
-      when 401; { :message => "Unauthorized" }
-      when 403; { :message => "Forbidden" }
-      when 404; { :message => "Not Found" }
-      when 405; { :message => "Method Not Allowed" }
-      when 406; { :message => "Not Acceptable" }
-      when 500; { :message => "Internal Server Error" }
-      when 502; { :message => "Backend Server Error" }
-      when 501; { :message => "Not Supported" }
-    end
-  end
-
-  def new_blob_form_url(bucket)
-    bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
-  end
-end
diff --git a/server/lib/deltacloud/helpers/auth_helper.rb b/server/lib/deltacloud/helpers/auth_helper.rb
new file mode 100644
index 0000000..eef2521
--- /dev/null
+++ b/server/lib/deltacloud/helpers/auth_helper.rb
@@ -0,0 +1,73 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# Lazy Basic HTTP authentication. Authentication is only forced when the
+# credentials are actually needed.
+
+module Sinatra
+  module AuthHelper
+    class LazyCredentials
+      def initialize(app)
+        @app = app
+        @provided = false
+      end
+
+      def user
+        credentials!
+        @user
+      end
+
+      def password
+        credentials!
+        @password
+      end
+
+      def provided?
+        @provided
+      end
+
+      private
+      def credentials!
+        if ENV["API_USER"] && ENV["API_PASSWORD"]
+          @user = ENV["API_USER"]
+          @password = ENV["API_PASSWORD"]
+          @provided = true
+        end
+        unless provided?
+          auth = Rack::Auth::Basic::Request.new(@app.request.env)
+          @app.authorize! unless auth.provided? && auth.basic? && auth.credentials
+          @user = auth.credentials[0]
+          @password = auth.credentials[1]
+          @provided = true
+        end
+      end
+
+    end
+
+    def authorize!
+      r = "#{Thread.current[:driver]}-deltacloud@#{ENV['HOSTNAME']}"
+      response['WWW-Authenticate'] = %(Basic realm="#{r}")
+      throw(:halt, [401, report_error(401)])
+    end
+
+    # Request the current user's credentials. Actual credentials are only
+    # requested when an attempt is made to get the user name or password
+    def credentials
+      LazyCredentials.new(self)
+    end
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/blob_stream.rb b/server/lib/deltacloud/helpers/blob_stream.rb
deleted file mode 100644
index df5cdc6..0000000
--- a/server/lib/deltacloud/helpers/blob_stream.rb
+++ /dev/null
@@ -1,213 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-include Deltacloud
-begin
-  require 'eventmachine'
-  #--
-  # based on the example from
-  #   http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/
-  #--
-  class BlobStream
-    AsyncResponse = [-1, {}, []].freeze
-    def self.call(env, credentials, params)
-      body = DeferrableBody.new
-      #Get the headers out asap. Don't specify a content-type let
-      #the client guess and if they can't they SHOULD default to
-      #'application/octet-stream' anyway as per:
-      #http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
-      EM.next_tick { env['async.callback'].call [200, {
-        'Content-Type' => "#{params['content_type']}",
-        'Content-Disposition' => params["content_disposition"],
-        'Content-Length' => "#{params['content_length']}"}, body]
-      }
-      #call the driver from here. the driver method yields for every chunk
-      #of blob it receives. Then use body.call to write that chunk as received.
-      driver.blob_data(credentials, params[:bucket], params[:blob], params) {|chunk| body.call ["#{chunk}"]} #close blob_data block
-      body.succeed
-      AsyncResponse # Tell Thin to not close connection & work other requests
-    end
-  end
-
-  class DeferrableBody
-    include EventMachine::Deferrable
-
-    def call(body)
-      body.each do |chunk|
-        @body_callback.call(chunk)
-      end
-    end
-
-    def each(&blk)
-      @body_callback = blk
-    end
-  end
-rescue LoadError => e
-  # EventMachine isn't available, disable blob streaming
-  class BlobStream
-    def self.call(env, credentials, params)
-      raise NotImplementedError.new("Blob streaming is only supported under Thin")
-    end
-  end
-end
-
-module BlobHelper
-
-  def self.extract_blob_metadata_hash(env_hash)
-    meta_array = env_hash.select{|k,v| k.match(/^HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i)}
-    metadata = meta_array.inject({}){ |result, array| result[array.first.upcase] = array.last; result}
-    metadata
-  end
-
-DELTACLOUD_BLOBMETA_HEADER = /HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i
-
-  #e.g. from HTTP-X-Deltacloud-Blobmeta-FOO:BAR to amz-meta-FOO:BAR
-  def self.rename_metadata_headers(metadata, rename_to)
-    metadata.gsub_keys(DELTACLOUD_BLOBMETA_HEADER, rename_to)
-  end
-
-end
-
-#Monkey patch for streaming blobs:
-# Normally a client will upload a blob to deltacloud and thin will put
-# this into a tempfile. Then deltacloud would stream up to the provider:
-#   i.e.  client =-->>TEMP_FILE-->> deltacloud =-->>STREAM-->> provider
-# Instead we want to recognise that this is a 'PUT blob' operation and
-# start streaming to the provider as the request is received:
-#   i.e.  client =-->>STREAM-->> deltacloud =-->>STREAM-->> provider
-module Thin
-  class Request
-
-    alias_method :move_body_to_tempfile_orig, :move_body_to_tempfile if defined?(Thin::Response)
-    private
-      def move_body_to_tempfile
-        if BlobStreamIO::is_put_blob(self)
-          @body = BlobStreamIO.new(self)
-        else
-          move_body_to_tempfile_orig
-        end
-      end
-
-  end
-end
-
-require 'net/http'
-require 'net/https'
-#monkey patch for Net:HTTP
-module Net
-  class HTTP
-
-    alias :request_orig :request
-
-    def request(req, body = nil, blob_stream = nil, &block)
-      unless blob_stream
-        return request_orig(req, body, &block)
-      end
-      @blob_req = req
-      do_start #start the connection
-
-      req.set_body_internal body
-      begin_transport req
-      req.write_header_m @socket,@curr_http_version, edit_path(req.path)
-      @socket
-    end
-
-    class Put < HTTPRequest
-      def write_header_m(sock, ver, path)
-        write_header(sock, ver, path)
-      end
-    end
-
-    def end_request
-      begin
-        res = HTTPResponse.read_new(@socket)
-      end while res.kind_of?(HTTPContinue)
-      res.reading_body(@socket, @blob_req.response_body_permitted?) {
-                                          yield res if block_given? }
-      end_transport @blob_req, res
-      do_finish
-      res
-    end
-  end
-
-end
-
-require 'base64'
-class BlobStreamIO
-
-  attr_accessor :size, :provider, :sock
-
-  def initialize(request)
-    @client_request = request
-    @size = 0
-    bucket, blob = parse_bucket_blob(request.env["PATH_INFO"])
-    user, password = parse_credentials(request.env['HTTP_AUTHORIZATION'])
-    content_type = request.env['CONTENT_TYPE'] || ""
-    #deal with blob_metadata: (X-Deltacloud-Blobmeta-name: value)
-    user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
-    @content_length = request.env['CONTENT_LENGTH']
-    @http, provider_request = driver.blob_stream_connection({:user=>user,
-       :password=>password, :bucket=>bucket, :blob=>blob, :metadata=> user_meta,
-       :content_type=>content_type, :content_length=>@content_length })
-    @content_length = @content_length.to_i #for comparison of size in '<< (data)'
-    @sock = @http.request(provider_request, nil, true)
-  end
-
-  def << (data)
-    @sock.write(data)
-    @size += data.length
-    if (@size >= @content_length)
-      result = @http.end_request
-      if result.is_a?(Net::HTTPSuccess)
-        @client_request.env["BLOB_SUCCESS"] = "true"
-      else
-        @client_request.env["BLOB_FAIL"] = result.body
-      end
-    end
-  end
-
-  def rewind
-  end
-
-  #use the Request.env hash (populated by the ThinParser) to determine whether
-  #this is a post blob operation. By definition, only get here with a body of
-  # > 112kbytes - thin/lib/thin/request.rb:12 MAX_BODY = 1024 * (80 + 32)
-  def self.is_put_blob(request = nil)
-    path = request.env['PATH_INFO']
-    method = request.env['REQUEST_METHOD']
-    if ( path =~ /^#{Regexp.escape(settings.root_url)}\/buckets/ && method == 'PUT' )
-      return true
-    else
-      return false
-    end
-  end
-
-  private
-
-  def parse_bucket_blob(request_string)
-    array = request_string.split("/")
-    blob = array.pop
-    bucket = array.pop
-    return bucket, blob
-  end
-
-  def parse_credentials(request_string)
-    decoded = Base64.decode64(request_string.split('Basic ').last)
-    key = decoded.split(':').first
-    pass = decoded.split(':').last
-    return key, pass
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/blob_stream_helper.rb b/server/lib/deltacloud/helpers/blob_stream_helper.rb
new file mode 100644
index 0000000..3830c60
--- /dev/null
+++ b/server/lib/deltacloud/helpers/blob_stream_helper.rb
@@ -0,0 +1,214 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+include Deltacloud
+
+begin
+  require 'eventmachine'
+  #--
+  # based on the example from
+  #   http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/
+  #--
+  class BlobStream
+    AsyncResponse = [-1, {}, []].freeze
+    def self.call(env, credentials, params)
+      body = DeferrableBody.new
+      #Get the headers out asap. Don't specify a content-type let
+      #the client guess and if they can't they SHOULD default to
+      #'application/octet-stream' anyway as per:
+      #http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
+      EM.next_tick { env['async.callback'].call [200, {
+        'Content-Type' => "#{params['content_type']}",
+        'Content-Disposition' => params["content_disposition"],
+        'Content-Length' => "#{params['content_length']}"}, body]
+      }
+      #call the driver from here. the driver method yields for every chunk
+      #of blob it receives. Then use body.call to write that chunk as received.
+      driver.blob_data(credentials, params[:bucket], params[:blob], params) {|chunk| body.call ["#{chunk}"]} #close blob_data block
+      body.succeed
+      AsyncResponse # Tell Thin to not close connection & work other requests
+    end
+  end
+
+  class DeferrableBody
+    include EventMachine::Deferrable
+
+    def call(body)
+      body.each do |chunk|
+        @body_callback.call(chunk)
+      end
+    end
+
+    def each(&blk)
+      @body_callback = blk
+    end
+  end
+rescue LoadError => e
+  # EventMachine isn't available, disable blob streaming
+  class BlobStream
+    def self.call(env, credentials, params)
+      raise NotImplementedError.new("Blob streaming is only supported under Thin")
+    end
+  end
+end
+
+module BlobHelper
+
+  def self.extract_blob_metadata_hash(env_hash)
+    meta_array = env_hash.select{|k,v| k.match(/^HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i)}
+    metadata = meta_array.inject({}){ |result, array| result[array.first.upcase] = array.last; result}
+    metadata
+  end
+
+DELTACLOUD_BLOBMETA_HEADER = /HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i
+
+  #e.g. from HTTP-X-Deltacloud-Blobmeta-FOO:BAR to amz-meta-FOO:BAR
+  def self.rename_metadata_headers(metadata, rename_to)
+    metadata.gsub_keys(DELTACLOUD_BLOBMETA_HEADER, rename_to)
+  end
+
+end
+
+#Monkey patch for streaming blobs:
+# Normally a client will upload a blob to deltacloud and thin will put
+# this into a tempfile. Then deltacloud would stream up to the provider:
+#   i.e.  client =-->>TEMP_FILE-->> deltacloud =-->>STREAM-->> provider
+# Instead we want to recognise that this is a 'PUT blob' operation and
+# start streaming to the provider as the request is received:
+#   i.e.  client =-->>STREAM-->> deltacloud =-->>STREAM-->> provider
+module Thin
+  class Request
+
+    alias_method :move_body_to_tempfile_orig, :move_body_to_tempfile if defined?(Thin::Response)
+    private
+      def move_body_to_tempfile
+        if BlobStreamIO::is_put_blob(self)
+          @body = BlobStreamIO.new(self)
+        else
+          move_body_to_tempfile_orig
+        end
+      end
+
+  end
+end
+
+require 'net/http'
+require 'net/https'
+#monkey patch for Net:HTTP
+module Net
+  class HTTP
+
+    alias :request_orig :request
+
+    def request(req, body = nil, blob_stream = nil, &block)
+      unless blob_stream
+        return request_orig(req, body, &block)
+      end
+      @blob_req = req
+      do_start #start the connection
+
+      req.set_body_internal body
+      begin_transport req
+      req.write_header_m @socket,@curr_http_version, edit_path(req.path)
+      @socket
+    end
+
+    class Put < HTTPRequest
+      def write_header_m(sock, ver, path)
+        write_header(sock, ver, path)
+      end
+    end
+
+    def end_request
+      begin
+        res = HTTPResponse.read_new(@socket)
+      end while res.kind_of?(HTTPContinue)
+      res.reading_body(@socket, @blob_req.response_body_permitted?) {
+                                          yield res if block_given? }
+      end_transport @blob_req, res
+      do_finish
+      res
+    end
+  end
+
+end
+
+require 'base64'
+class BlobStreamIO
+
+  attr_accessor :size, :provider, :sock
+
+  def initialize(request)
+    @client_request = request
+    @size = 0
+    bucket, blob = parse_bucket_blob(request.env["PATH_INFO"])
+    user, password = parse_credentials(request.env['HTTP_AUTHORIZATION'])
+    content_type = request.env['CONTENT_TYPE'] || ""
+    #deal with blob_metadata: (X-Deltacloud-Blobmeta-name: value)
+    user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
+    @content_length = request.env['CONTENT_LENGTH']
+    @http, provider_request = driver.blob_stream_connection({:user=>user,
+       :password=>password, :bucket=>bucket, :blob=>blob, :metadata=> user_meta,
+       :content_type=>content_type, :content_length=>@content_length })
+    @content_length = @content_length.to_i #for comparison of size in '<< (data)'
+    @sock = @http.request(provider_request, nil, true)
+  end
+
+  def << (data)
+    @sock.write(data)
+    @size += data.length
+    if (@size >= @content_length)
+      result = @http.end_request
+      if result.is_a?(Net::HTTPSuccess)
+        @client_request.env["BLOB_SUCCESS"] = "true"
+      else
+        @client_request.env["BLOB_FAIL"] = result.body
+      end
+    end
+  end
+
+  def rewind
+  end
+
+  #use the Request.env hash (populated by the ThinParser) to determine whether
+  #this is a post blob operation. By definition, only get here with a body of
+  # > 112kbytes - thin/lib/thin/request.rb:12 MAX_BODY = 1024 * (80 + 32)
+  def self.is_put_blob(request = nil)
+    path = request.env['PATH_INFO']
+    method = request.env['REQUEST_METHOD']
+    if ( path =~ /^#{Regexp.escape(Deltacloud::API.settings.root_url)}\/buckets/ && method == 'PUT' )
+      return true
+    else
+      return false
+    end
+  end
+
+  private
+
+  def parse_bucket_blob(request_string)
+    array = request_string.split("/")
+    blob = array.pop
+    bucket = array.pop
+    return bucket, blob
+  end
+
+  def parse_credentials(request_string)
+    decoded = Base64.decode64(request_string.split('Basic ').last)
+    key = decoded.split(':').first
+    pass = decoded.split(':').last
+    return key, pass
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/conversion_helper.rb b/server/lib/deltacloud/helpers/conversion_helper.rb
deleted file mode 100644
index 310ba4b..0000000
--- a/server/lib/deltacloud/helpers/conversion_helper.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-require 'deltacloud/base_driver'
-
-module ConversionHelper
-
-  def convert_to_json(type, obj)
-    if ( [ :image, :realm, :instance, :storage_volume, :storage_snapshot, :hardware_profile, :key, :bucket, :blob, :firewall, :load_balancer, :address ].include?( type ) )
-      if Array.eql?(obj.class)
-        data = obj.collect do |o|
-          o.to_hash.merge({ :href => self.send(:"#{type}_url", type.eql?(:hardware_profile) ? o.name : o.id ) })
-        end
-        type = type.to_s.pluralize
-      else
-        data = obj.to_hash
-        if type == :blob
-          data.merge!({ :href => self.send(:"bucket_url", "#{data[:bucket]}/#{data[:id]}" ) })
-        else
-          data.merge!({ :href => self.send(:"#{type}_url", data[:id]) })
-          if data.has_key?(:hardware_profiles)
-            data[:hardware_profiles] = data[:hardware_profiles].inject([]){|res, hwp| res << {hwp.name => {:href => self.send(:"hardware_profile_url", hwp.name)}}; res }
-          end
-        end
-      end
-      return { :"#{type}" => data }.to_json
-    end
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb b/server/lib/deltacloud/helpers/deltacloud_helper.rb
new file mode 100644
index 0000000..83741f9
--- /dev/null
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -0,0 +1,273 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Helpers
+  module Application
+
+    require 'benchmark'
+
+    def self.included(klass)
+      klass.class_eval do
+        set :root_url, API_ROOT_URL
+        include Sinatra::Rabbit
+        Sinatra::Rabbit.set :root_path, root_url+'/'
+      end
+    end
+
+    def instance_action_method(action)
+      action_method(action, Sinatra::Rabbit::InstancesCollection)
+    end
+
+    def action_method(action, collection)
+      http_method = collection.operation(action).http_method
+      http_method || Sinatra::Rabbit::BaseCollection.http_method_for(action)
+    end
+
+    def filter_all(model)
+      filter = {}
+      filter.merge!(:id => params[:id]) if params[:id]
+      filter.merge!(:architecture => params[:architecture]) if params[:architecture]
+      filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
+      filter.merge!(:state => params[:state]) if params[:state]
+      filter = {} if filter.keys.size.eql?(0)
+      singular = model.to_s.singularize.to_sym
+      begin
+        @benchmark = Benchmark.measure do
+          @elements = driver.send(model.to_sym, credentials, filter)
+        end
+      rescue
+        @exception = $!
+      end
+      if @elements
+        headers['X-Backend-Runtime'] = @benchmark.real.to_s
+        instance_variable_set(:"@#{model}", @elements)
+        respond_to do |format|
+          format.html { haml :"#{model}/index" }
+          format.xml { haml :"#{model}/index" }
+          format.json { @media_type=:xml; to_json(haml(:"#{model}/index")) }
+        end
+      else
+        report_error(@exception.respond_to?(:code) ? @exception.code : 500)
+      end
+    end
+
+    def xml_to_json(model)
+      @media_type = :xml
+      to_json(haml(:"#{model}"))
+    end
+
+    def to_json(xml)
+      Crack::XML.parse(xml).to_json
+    end
+
+    def show(model)
+      @benchmark = Benchmark.measure do
+        @element = driver.send(model, credentials, { :id => params[:id]} )
+      end
+      headers['X-Backend-Runtime'] = @benchmark.real.to_s
+      instance_variable_set("@#{model}", @element)
+      if @element
+        respond_to do |format|
+          format.html { haml :"#{model.to_s.pluralize}/show" }
+          format.xml { haml :"#{model.to_s.pluralize}/show" }
+          format.json { @media_type=:xml; to_json(haml(:"#{model.to_s.pluralize}/show")) }
+        end
+      else
+        report_error(404)
+      end
+    end
+
+    def report_error(code=nil)
+      @error, @code = (request.env['sinatra.error'] || @exception), code
+      @code = 500 if not @code and not @error.class.method_defined? :code
+      response.status = @code || @error.code
+      respond_to do |format|
+        format.xml {  haml :"errors/#{@code || @error.code}", :layout => false }
+        format.html { haml :"errors/#{@code || @error.code}", :layout => :error }
+      end
+    end
+
+    def instance_action(name)
+      original_instance = driver.instance(credentials, :id => params[:id])
+
+      # If original instance doesn't include called action
+      # return with 405 error (Method is not Allowed)
+      unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
+        return report_error(405)
+      end
+
+      @benchmark = Benchmark.measure do
+        @instance = driver.send(:"#{name}_instance", credentials, params[:id])
+      end
+
+      headers['X-Backend-Runtime'] = @benchmark.real.to_s
+      status 202
+
+      if name == :destroy
+        respond_to do |format|
+          format.xml { return 204 }
+          format.json { return 204 }
+          format.html { return redirect(instances_url) }
+        end
+      end
+
+      if @instance.class != Instance
+        response['Location'] = instance_url(params[:id])
+        halt
+      end
+
+      respond_to do |format|
+        format.xml { haml :"instances/show" }
+        format.html { haml :"instances/show" }
+        format.json {convert_to_json(:instance, @instance) }
+      end
+    end
+
+    def cdata(text = nil, &block)
+      text ||= capture_haml(&block)
+      "<![CDATA[#{text.strip}]]>"
+    end
+
+    def render_cdata(text)
+      "<![CDATA[#{text.strip}]]>"
+    end
+
+    def link_to_action(action, url, method)
+      capture_haml do
+        haml_tag :form, :method => :post, :action => url, :class => [:link, method], :'data-ajax' => 'false' do
+          haml_tag :input, :type => :hidden, :name => '_method', :value => method
+          haml_tag :button, :type => :submit, :'data-ajax' => 'false', :'data-inline' => "true" do
+            haml_concat action
+          end
+        end
+      end
+    end
+
+    def link_to_format(format)
+      return unless request.env['REQUEST_URI']
+      uri = request.env['REQUEST_URI']
+      return if uri.include?('format=')
+      uri += uri.include?('?') ? "&format=#{format}" : "?format=#{format}"
+      capture_haml do
+        haml_tag :a, :href => uri, :'data-ajax' => 'false', :'data-icon' => 'grid' do
+          haml_concat format.to_s.upcase
+        end
+      end
+    end
+
+    def image_for_state(state)
+      state_img = "stopped" if (state!='RUNNING' or state!='PENDING')
+      capture_haml do
+        haml_tag :img, :src => "/images/#{state}" % state.downcase, :title => state
+      end
+    end
+
+    # Reverse the entrypoints hash for a driver from drivers.yaml; note that
+    # +d+ is a hash, not an actual driver object
+    def driver_provider(d)
+      result = {}
+      if d[:entrypoints]
+        d[:entrypoints].each do |kind, details|
+          details.each do |prov, url|
+            result[prov] ||= {}
+            result[prov][kind] = url
+          end
+        end
+      end
+      result
+    end
+
+    def header(title, opts={}, &block)
+      opts[:theme] ||= 'b'
+      opts[:back] ||= 'true'
+      capture_haml do
+        haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme], :'data-add-back-btn' => opts[:back] do
+          haml_tag :a, :'data-rel' => :back do
+            haml_concat "Back"
+          end if opts[:back] == 'true'
+          haml_tag :h1 do
+            haml_concat title
+          end
+          block.call if block_given?
+        end
+      end
+    end
+
+    def subheader(title, opts={})
+      opts[:theme] ||= 'a'
+      capture_haml do
+        haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme] do
+          haml_tag :p, :class => 'inner-right' do
+            haml_concat title
+          end
+        end
+      end
+    end
+
+    def translate_error_code(code)
+      case code
+      when 400; { :message => "Bad Request" }
+      when 401; { :message => "Unauthorized" }
+      when 403; { :message => "Forbidden" }
+      when 404; { :message => "Not Found" }
+      when 405; { :message => "Method Not Allowed" }
+      when 406; { :message => "Not Acceptable" }
+      when 500; { :message => "Internal Server Error" }
+      when 502; { :message => "Backend Server Error" }
+      when 501; { :message => "Not Supported" }
+      end
+    end
+
+    def new_blob_form_url(bucket)
+      bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
+    end
+
+    def format_hardware_property(prop)
+      return "&empty;" unless prop
+      u = hardware_property_unit(prop)
+      case prop.kind
+      when :range
+        "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} #{u})"
+      when :enum
+        prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: #{prop.default} #{u})"
+      else
+        "#{prop.value} #{u}"
+      end
+    end
+
+    def format_instance_profile(ip)
+      o = ip.overrides.collect do |p, v|
+        u = hardware_property_unit(p)
+        "#{p} = #{v} #{u}"
+      end
+      if o.empty?
+        ""
+      else
+        "with #{o.join(", ")}"
+      end
+    end
+
+    private
+    def hardware_property_unit(prop)
+      u = ::Deltacloud::HardwareProfile::unit(prop)
+      u = "" if ["label", "count"].include?(u)
+      u = "vcpus" if prop == :cpu
+      u
+    end
+
+
+
+  end
+end
diff --git a/server/lib/deltacloud/helpers/driver_helper.rb b/server/lib/deltacloud/helpers/driver_helper.rb
new file mode 100644
index 0000000..f620744
--- /dev/null
+++ b/server/lib/deltacloud/helpers/driver_helper.rb
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Helpers
+
+  module Drivers
+
+    def driver_symbol
+      driver_name.to_sym
+    end
+
+    def driver_name
+      Thread.current[:driver] ||= ENV['API_DRIVER']
+    end
+
+    def driver_class_name
+      driver_name.camelize
+    end
+
+    def driver_source_name
+      File.join('..', 'drivers', driver_name, driver_name + '_driver.rb')
+    end
+
+    def driver_class
+      begin
+        m = Deltacloud::Drivers.const_get(driver_class_name)
+        m.const_get(driver_class_name + "Driver").new
+      rescue NameError
+        raise "[ERROR] The driver class name is not defined as #{driver_class_name}Driver"
+      end
+    end
+
+    def driver
+      $:.unshift File.join(File.dirname(__FILE__), '..', '..')
+      begin
+        require_relative driver_source_name
+        driver_class
+      rescue LoadError
+        raise "[ERROR] The driver '#{driver_name}' is unknown or not installed (#{driver_source_name})"
+      end
+    end
+
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/hardware_profiles_helper.rb b/server/lib/deltacloud/helpers/hardware_profiles_helper.rb
deleted file mode 100644
index 862d680..0000000
--- a/server/lib/deltacloud/helpers/hardware_profiles_helper.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module HardwareProfilesHelper
-
-  def format_hardware_property(prop)
-    return "&empty;" unless prop
-    u = hardware_property_unit(prop)
-    case prop.kind
-      when :range
-      "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} #{u})"
-      when :enum
-      prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: #{prop.default} #{u})"
-      else
-      "#{prop.value} #{u}"
-    end
-  end
-
-  def format_instance_profile(ip)
-    o = ip.overrides.collect do |p, v|
-      u = hardware_property_unit(p)
-      "#{p} = #{v} #{u}"
-    end
-    if o.empty?
-      nil
-    else
-      "with #{o.join(", ")}"
-    end
-  end
-
-  #first by cpu - then by memory
-  def order_hardware_profiles(profiles)
-   #have to deal with opaque hardware profiles
-   uncomparables = profiles.select{|x| x.cpu.nil? or x.memory.nil? }
-   if uncomparables.empty?
-      profiles.sort_by{|a| [a.cpu.default, a.memory.default] }
-   else
-      (profiles - uncomparables).sort_by{|a| [a.cpu.default, a.memory.default] } + uncomparables
-   end
-  end
-
-  private
-
-  def hardware_property_unit(prop)
-    u = ::Deltacloud::HardwareProfile::unit(prop)
-    u = "" if ["label", "count"].include?(u)
-    u = "vcpus" if prop == :cpu
-    u
-  end
-end
diff --git a/server/lib/deltacloud/helpers/json_helper.rb b/server/lib/deltacloud/helpers/json_helper.rb
deleted file mode 100644
index aea16b6..0000000
--- a/server/lib/deltacloud/helpers/json_helper.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module JSONHelper
-
-  def json_features_for_entrypoint(entrypoint)
-    features = driver.features(entrypoint.first).collect { |feature| feature.name }
-    features.empty? ? {} : { :features => features }
-  end
-
-  def json_return_error(error)
-    error_output=Hash.new
-    error_output[:url]    =request.env['REQUEST_URI']
-    error_output[:status] =response.status
-    error_output[:message]=error.message if error
-    error_output.to_json
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/rabbit_helper.rb b/server/lib/deltacloud/helpers/rabbit_helper.rb
new file mode 100644
index 0000000..252abe2
--- /dev/null
+++ b/server/lib/deltacloud/helpers/rabbit_helper.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+Sinatra::Rabbit::Collection.class_eval do
+
+  def self.standard_index_operation
+    collection_name = @collection_name
+    operation :index, :with_capability => collection_name do
+      control { filter_all collection_name }
+    end
+  end
+
+  def self.standard_show_operation
+    collection_name = @collection_name
+    operation :show, :with_capability => collection_name do
+      control { show collection_name.to_s.singularize.intern }
+    end
+  end
+
+end
+
diff --git a/server/lib/deltacloud/helpers/url_helper.rb b/server/lib/deltacloud/helpers/url_helper.rb
new file mode 100644
index 0000000..87bc93e
--- /dev/null
+++ b/server/lib/deltacloud/helpers/url_helper.rb
@@ -0,0 +1,112 @@
+#
+# Based on https://github.com/emk/sinatra-url-for/
+# Commit 1df339284203f8f6ed8d
+#
+# Original license:
+# Copyright (C) 2009 Eric Kidd
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Sinatra
+  module UrlForHelper
+
+    require 'uri'
+
+    def method_missing(name, *args)
+      if name.to_s =~ /^([\w\_]+)_url$/
+        if args.size > 0
+          t = $1
+          if t =~ /^(stop|reboot|destroy|start|attach|detach)_/
+            api_url_for(t.pluralize.split('_').last + '/' + args.first + '/' + $1, :full)
+          else
+            api_url_for(t.pluralize, :full) + '/' + "#{args.first}"
+          end
+        else
+          api_url_for($1, :full)
+        end
+      else
+        super
+      end
+    end
+
+    def api_url_for(url_fragment, mode=:path_only)
+      matrix_params = ''
+      if request.params['api']
+        matrix_params += ";provider=%s" % request.params['api']['provider'] if request.params['api']['provider']
+        matrix_params += ";driver=%s" % request.params['api']['driver'] if request.params['api']['driver']
+      end
+      url_fragment = "/#{url_fragment}" unless url_fragment =~ /^\// # There is no need to prefix URI with '/'
+      if mode == :path_only
+        url_for "#{settings.root_url}#{matrix_params}#{url_fragment}", mode
+      else
+        url_for "#{matrix_params}#{url_fragment}", :full
+      end
+    end
+
+    # Construct a link to +url_fragment+, which should be given relative to
+    # the base of this Sinatra app.  The mode should be either
+    # <code>:path_only</code>, which will generate an absolute path within
+    # the current domain (the default), or <code>:full</code>, which will
+    # include the site name and port number.  (The latter is typically
+    # necessary for links in RSS feeds.)  Example usage:
+    #
+    #   url_for "/"            # Returns "/myapp/"
+    #   url_for "/foo"         # Returns "/myapp/foo"
+    #   url_for "/foo", :full  # Returns "http://example.com/myapp/foo"
+    #--
+    # See README.rdoc for a list of some of the people who helped me clean
+    # up earlier versions of this code.
+    def url_for url_fragment, mode=:path_only
+      case mode
+      when :path_only
+        base = request.script_name
+      when :full
+        scheme = request.scheme
+        port = request.port
+        request_host = request.host
+        if request.env['HTTP_X_FORWARDED_FOR']
+          scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || scheme
+          port = request.env['HTTP_X_FORWARDED_PORT']
+          request_host = request.env['HTTP_X_FORWARDED_HOST']
+        end
+        if (port.nil? || port == "" ||
+            (scheme == 'http' && port.to_s == '80') ||
+            (scheme == 'https' && port.to_s == '443'))
+          port = ""
+        else
+          port = ":#{port}"
+        end
+        base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
+      else
+        raise TypeError, "Unknown url_for mode #{mode}"
+      end
+      uri_parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
+      url_escape = uri_parser.escape(url_fragment)
+      # Don't add the base fragment if url_for gets called more than once
+      # per url or the url_fragment passed in is an absolute url
+      if url_escape.match(/^#{base}/) or url_escape.match(/^http/)
+        url_escape
+      else
+        "#{base}#{url_escape}"
+      end
+    end
+  end
+
+end
diff --git a/server/lib/deltacloud/method_serializer.rb b/server/lib/deltacloud/method_serializer.rb
deleted file mode 100644
index eec9abe..0000000
--- a/server/lib/deltacloud/method_serializer.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'base64'
-require 'digest'
-
-module MethodSerializer
-
-  module Cache
-
-    def cache_dir
-      storage_dir = $methods_cache_dir || File.join(File.dirname(__FILE__), 'cache')
-      class_dir = self.class.name.split('::').last
-      class_dir ||= self.class.name
-      File.join(storage_dir, class_dir.downcase)
-    end
-
-    def serialize_data(method_name, args, data)
-      File.open(cache_file_name(method_name, args), 'w') do |f|
-        f.puts(Base64.encode64(Marshal.dump(data)))
-      end
-      return data
-    end
-
-    def deserialize_data(method_name, args)
-      begin
-        data = File.readlines(cache_file_name(method_name, args)).join
-        Marshal.load(Base64.decode64(data))
-      rescue Errno::ENOENT
-        return false
-      end
-    end
-
-    def args_hash(args)
-      if args.class == Hash
-        args = args.to_a.collect {|i| [i[0].to_s, i[1]]}.sort
-      end
-      Digest::SHA1.hexdigest(args.to_s)
-    end
-
-    def cache_file_name(method_name, args)
-      FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
-      method_name = $scenario_prefix ? "#{$scenario_prefix}_#{method_name}" : method_name
-      File.join(cache_dir, "#{method_name}.#{args_hash(args)}")
-    end
-
-    def self.wrap_methods(c, opts={})
-      $methods_cache_dir = opts[:cache_dir]
-      $scenario_prefix = nil
-      c.class_eval do
-        cached_methods.each do |m|
-          next if c.instance_methods(false).include?("original_#{m}")
-          alias_method "original_#{m}".to_sym, m.to_sym
-          define_method m.to_sym do |*args|
-            args = args.first if args.size.eql?(1) and not args.first.class.eql?(Array)
-            output = deserialize_data(m, args)
-            unless output
-              output = method("original_#{m}".to_sym).to_proc[args]
-              return serialize_data(m, args, output)
-            else
-              return output
-            end
-          end
-        end
-      end
-    end
-
-  end
-
-end
diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index c6835a9..c2cc0e3 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -16,8 +16,6 @@
 
 class Instance < BaseModel
 
-  include ApplicationHelper
-
   attr_accessor :owner_id
   attr_accessor :image_id
   attr_accessor :name
diff --git a/server/lib/deltacloud/models/key.rb b/server/lib/deltacloud/models/key.rb
index 86a6283..64c4cc7 100644
--- a/server/lib/deltacloud/models/key.rb
+++ b/server/lib/deltacloud/models/key.rb
@@ -23,6 +23,10 @@ class Key < BaseModel
   attr_accessor :pem_rsa_key
   attr_accessor :state
 
+  def name
+    @name || @id
+  end
+
   def is_password?
     true if @credential_type.eql?(:password)
   end
diff --git a/server/lib/deltacloud/validation.rb b/server/lib/deltacloud/validation.rb
deleted file mode 100644
index 3d29225..0000000
--- a/server/lib/deltacloud/validation.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud::Validation
-
-  class Param
-    attr_reader :name, :klass, :type, :options, :description
-
-    def initialize(args)
-      @name = args[0]
-      @klass = args[1] || :string
-      @type = args[2] || :optional
-      @options = args[3] || []
-      @description = args[4] || ''
-    end
-
-    def required?
-      type.eql?(:required)
-    end
-
-    def optional?
-      type.eql?(:optional)
-    end
-
-    def valid_value?(value)
-      true if (options.kind_of?(Range) or options.kind_of?(Array)) and options.include?(value)
-      true if options.kind_of?(String) and not options.empty?
-    end
-
-    def valid_hwp_value?(profile, value)
-      profile.property(@name.to_s.gsub(/^hwp_/, '')).valid?(value)
-    end
-
-    def hwp_property?
-      true if name.to_s =~ /^hwp_(cpu|memory|storage|architecture)/
-    end
-  end
-
-  def param(*args)
-    raise "Duplicate param #{args[0]} #{params.inspect} #{self.class.name}" if params[args[0]]
-    p = Param.new(args)
-    params[p.name] = p
-  end
-
-  def params
-    @params ||= {}
-    @params
-  end
-
-  # Add the parameters in hash +new+ to already existing parameters. If
-  # +new+ contains a parameter with an already existing name, the old
-  # definition is clobbered.
-  def add_params(new)
-    # We do not check for duplication on purpose: multiple calls
-    # to add_params should be cumulative
-    new.each { |p|  @params[p.name] = p }
-  end
-
-  def each_param(&block)
-    params.each_value { |p| yield p }
-  end
-
-  def validate(current_driver, all_params, values, credentials)
-    all_params.each do |key, p|
-      if p.required? and not values[p.name]
-        raise validation_exception "Required parameter #{p.name} not found"
-      end
-      next unless values[p.name]
-      if p.hwp_property?
-        profile = current_driver.hardware_profile(credentials, values['hwp_id'])
-        raise validation_exception("Unknown hardware profile selected #{values['hwp_id']}") unless profile
-        unless p.valid_hwp_value?(profile, values[p.name])
-          raise validation_exception("Hardware profile property #{p.name} has invalid value #{values[p.name]}")
-        end
-      else
-        if not p.options.empty? and p.valid_value?(values[p.name])
-          raise validation_exception("Parameter #{p.name} has value #{values[p.name]} which is not in #{p.options.join(", ")}")
-        end
-      end
-    end
-  end
-
-  def validation_exception(message)
-    Deltacloud::ExceptionHandler::ValidationFailure.new(StandardError.new(message))
-  end
-
-end
diff --git a/server/lib/sinatra/lazy_auth.rb b/server/lib/sinatra/lazy_auth.rb
deleted file mode 100644
index fb94dd9..0000000
--- a/server/lib/sinatra/lazy_auth.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-
-# Lazy Basic HTTP authentication. Authentication is only forced when the
-# credentials are actually needed.
-module Sinatra
-  module LazyAuth
-    class LazyCredentials
-      def initialize(app)
-        @app = app
-        @provided = false
-      end
-
-      def user
-        credentials!
-        @user
-      end
-
-      def password
-        credentials!
-        @password
-      end
-
-      def provided?
-        @provided
-      end
-
-      private
-      def credentials!
-        if ENV["API_USER"] && ENV["API_PASSWORD"]
-          @user = ENV["API_USER"]
-          @password = ENV["API_PASSWORD"]
-          @provided = true
-        end
-        unless provided?
-          auth = Rack::Auth::Basic::Request.new(@app.request.env)
-          @app.authorize! unless auth.provided? && auth.basic? && auth.credentials
-          @user = auth.credentials[0]
-          @password = auth.credentials[1]
-          @provided = true
-        end
-      end
-
-    end
-
-    def authorize!
-      r = "#{driver_symbol}-deltacloud@#{HOSTNAME}"
-      response['WWW-Authenticate'] = %(Basic realm="#{r}")
-      throw(:halt, [401, report_error(401)])
-    end
-
-    # Request the current user's credentials. Actual credentials are only
-    # requested when an attempt is made to get the user name or password
-    def credentials
-      LazyCredentials.new(self)
-    end
-  end
-
-  helpers LazyAuth
-end
diff --git a/server/lib/sinatra/rabbit.rb b/server/lib/sinatra/rabbit.rb
deleted file mode 100644
index 5c63fd9..0000000
--- a/server/lib/sinatra/rabbit.rb
+++ /dev/null
@@ -1,441 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-require 'sinatra/url_for'
-require 'deltacloud/validation'
-require 'deltacloud/backend_capability'
-
-module Sinatra
-
-  module Rabbit
-
-    def self.routes
-      @routes ||= []
-    end
-
-    class DuplicateParamException < Deltacloud::ExceptionHandler::DeltacloudException; end
-    class DuplicateOperationException < Deltacloud::ExceptionHandler::DeltacloudException; end
-    class DuplicateCollectionException < Deltacloud::ExceptionHandler::DeltacloudException; end
-    class UnsupportedCollectionException < Deltacloud::ExceptionHandler::DeltacloudException
-      def initialize
-        # The server understood the request, but is refusing to fulfill it. Authorization will not help and the request
-        # SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request
-        # has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish
-        # to make this information available to the client, the status code 404 (Not Found) can be used instead.
-        super(403, 'UnsupportedCollection', "Requested collection is not supported for current provider", [])
-      end
-    end
-
-    class Operation
-      attr_reader :name, :method, :collection, :member
-
-      include ::Deltacloud::BackendCapability
-      include ::Deltacloud::Validation
-      include ::ApplicationHelper
-
-      STANDARD = {
-        :new => { :method => :get, :member => false, :form => true },
-        :index => { :method => :get, :member => false },
-        :show =>  { :method => :get, :member => true },
-        :create => { :method => :post, :member => false },
-        :update => { :method => :put, :member => true },
-        :destroy => { :method => :delete, :member => true }
-      }
-
-      def initialize(coll, name, opts, &block)
-        @name = name.to_sym
-        opts = STANDARD[@name].merge(opts) if standard?
-        @path_generator = opts[:path_generator]
-        @collection, @standard = coll, opts[:standard]
-        raise "No method for operation #{name}" unless opts[:method]
-        @method = opts[:method].to_sym
-        @member = opts[:member]
-        @description = ""
-        instance_eval(&block) if block_given?
-        generate_documentation
-        generate_options
-      end
-
-      def http_method
-        @method
-      end
-
-      def standard?
-        STANDARD.keys.include?(name) || @standard
-      end
-
-      def form?
-        STANDARD[name] and STANDARD[name][:form]
-      end
-
-      def description(text="")
-        return @description if text.blank?
-        @description = text
-      end
-
-      def generate_documentation
-        coll, oper = @collection, self
-        Rabbit::routes << [:get, "#{settings.root_url}/docs/#{@collection.name}/#{@name}"]
-        ::Sinatra::Application.get("#{settings.root_url}/docs/#{@collection.name}/#{@name}") do
-          @collection, @operation = coll, oper
-          @features = driver.features_for_operation(coll.name, oper.name)
-          respond_to do |format|
-            format.html { haml :'docs/operation' }
-            format.xml { haml :'docs/operation' }
-          end
-        end
-      end
-
-      def generate_options
-        current_operation = self
-        Rabbit::routes << [:options, "#{settings.root_url}/#{current_operation.collection.name}/#{current_operation.name}"]
-        ::Sinatra::Application.options("#{settings.root_url}/#{current_operation.collection.name}/#{current_operation.name}") do
-          required_params = current_operation.effective_params(driver).collect do |name, validation|
-            name.to_s if validation.type.eql?(:required)
-          end.compact.join(',')
-          optional_params = current_operation.effective_params(driver).collect do |name, validation|
-            name.to_s if validation.type.eql?(:optional)
-          end.compact.join(',')
-          headers 'X-Required-Parameters' => required_params
-          headers 'X-Optional-Parameters' => optional_params
-          [200, '']
-        end
-      end
-
-      def control(&block)
-        op = self
-        @control = Proc.new do
-          op.collection.check_supported(driver)
-          op.check_capability(driver)
-          op.validate(driver, op.effective_params(driver), params, credentials)
-          instance_eval(&block)
-        end
-      end
-
-      def member?
-        if standard?
-          @member || STANDARD[name][:member]
-        else
-          @member
-        end
-      end
-
-      def path(args = {})
-        return @path_generator.call(self) if @path_generator
-        if member?
-          if standard?
-            "#{@collection.name}/:id"
-          else
-            "#{@collection.name}/:id/#{name}"
-          end
-        else
-          if form?
-            "#{@collection.name}/#{name}"
-          else
-            "#{@collection.name}"
-          end
-        end
-      end
-
-      def generate
-        Rabbit::routes << [@method, "#{settings.root_url}/#{path}"]
-        ::Sinatra::Application.send(@method, "#{settings.root_url}/#{path}", {}, &@control)
-        # Set up some Rails-like URL helpers
-        if name == :index
-          gen_route "#{@collection.name}_url"
-        elsif name == :show
-          gen_route "#{@collection.name.to_s.singularize}_url"
-        else
-          gen_route "#{name}_#{@collection.name.to_s.singularize}_url"
-        end
-      end
-
-      # Return a hash of all params, the params statically defined for this
-      # operation plus the params defined by any features in the +driver+
-      # that might modify this operation
-      def effective_params(driver)
-        driver.features(@collection.name).collect do |f|
-          f.decl.operation(@name)
-        end.flatten.select { |op| op }.inject(params.dup) do |result, fop|
-          fop.params.each_key do |k|
-            if result.has_key?(k)
-              raise DuplicateParamException, "Parameter '#{k}' for operation #{fop.name} in collection #{@collection.name}"
-            else
-              result[k] = fop.params[k]
-            end
-          end
-          result
-        end
-      end
-
-      private
-      def gen_route(name)
-        route_url = path
-        if @member
-          ::Sinatra::Application.send(:define_method, name) do |id, *args|
-            url = query_url(route_url, args[0])
-            api_url_for url.gsub(/:id/, id.to_s), :full
-          end
-        else
-          ::Sinatra::Application.send(:define_method, name) do |*args|
-            url = query_url(route_url, args[0])
-            api_url_for url, :full
-          end
-        end
-      end
-    end
-
-    class Collection
-      attr_reader :name, :operations, :subcollections
-
-      def initialize(name, options={}, &block)
-        @name = name
-        @description = ""
-        @operations, @subcollections = {}, {}
-        @global = options[:global] || false
-        instance_eval(&block) if block_given?
-        generate_documentation
-        generate_head
-        generate_options
-      end
-
-      def subcollection?
-        self.class == SubCollection
-      end
-
-      # Set/Return description for collection
-      # If first parameter is not present, full description will be
-      # returned.
-      def description(text='')
-        return @description if text.blank?
-        @description = text
-      end
-
-      # Mark this collection as global, i.e. independent of any specific
-      # driver
-      def global!
-        @global = true
-      end
-
-      # Return +true+ if this collection is global, i.e. independent of any
-      # specific driver
-      def global?
-        @global
-      end
-
-      def generate_head
-        current_collection = self
-        Rabbit::routes << [:head, "#{settings.root_url}/#{name}"]
-        ::Sinatra::Application.head("#{settings.root_url}/#{name}") do
-          methods_allowed = current_collection.operations.collect { |o| o[1].method.to_s.upcase }.uniq.join(',')
-          headers 'Allow' => "HEAD,OPTIONS,#{methods_allowed}"
-          [200, '']
-        end
-      end
-
-      def generate_options
-        current_collection = self
-        Rabbit::routes << [:options, "#{settings.root_url}/#{name}"]
-        ::Sinatra::Application.options("#{settings.root_url}/#{name}") do
-          operations_allowed = current_collection.operations.collect { |o| o[0] }.join(',')
-          headers 'X-Operations-Allowed' => operations_allowed
-          [200, '']
-        end
-      end
-
-      def generate_documentation
-        coll = self
-        Rabbit::routes << [:get, "#{settings.root_url}/docs/#{@name}"]
-        ::Sinatra::Application.get("#{settings.root_url}/docs/#{@name}") do
-          coll.check_supported(driver)
-          @collection = coll
-          @operations = coll.operations
-          @features = driver.features(coll.name)
-          respond_to do |format|
-            format.html { haml :'docs/collection' }
-            format.xml { haml :'docs/collection' }
-          end
-        end
-      end
-
-      # Add a new operation for this collection. For the standard REST
-      # operations :index, :show, :update, and :destroy, we already know
-      # what method to use and whether this is an operation on the URL for
-      # individual elements or for the whole collection.
-      #
-      # For non-standard operations, options must be passed:
-      #  :method : one of the HTTP methods
-      #  :member : whether this is an operation on the collection or an
-      #            individual element (FIXME: custom operations on the
-      #            collection will use a nonsensical URL) The URL for the
-      #            operation is the element URL with the name of the operation
-      #            appended
-      #
-      # This also defines a helper method like show_instance_url that returns
-      # the URL to this operation (in request context)
-      def operation(name, opts = {}, &block)
-        if @operations.keys.include?(name)
-          raise DuplicateOperationException::new(500, "DuplicateOperation", "Operation #{name} is already defined", [])
-        end
-        @operations[name] = Operation.new(self, name, opts, &block)
-      end
-
-      def collection(name, opts={}, &block)
-        if subcollections.keys.include?(name)
-          raise DuplicateOperationException::new(500, "DuplicateSubcollection", "Subcollection #{name} is already defined", [])
-        end
-        subcollections[name] = SubCollection.new(self, name, opts, &block)
-        subcollections[name].generate
-      end
-
-      def generate
-        operations.values.reject { |op| op.member }.each { |o| o.generate }
-        operations.values.select { |op| op.member }.each { |o| o.generate }
-        app = ::Sinatra::Application
-        collname = name # Work around Ruby's weird scoping/capture
-        app.send(:define_method, "#{name.to_s.singularize}_url") do |id|
-          api_url_for "#{collname}/#{id}", :full
-        end
-        if index_op = operations[:index]
-          app.send(:define_method, "#{name}_url") do
-            api_url_for index_op.path.gsub(/\/\?$/,''), :full
-          end
-        end
-      end
-
-      def check_supported(driver)
-        unless global? || driver.has_collection?(@name) || self.kind_of?(Sinatra::Rabbit::SubCollection)
-          raise UnsupportedCollectionException
-        end
-      end
-    end
-
-    class SubCollection < Collection
-
-      attr_accessor :parent
-
-      def initialize(parent, name, opts={}, &block)
-        self.parent = parent
-        super(name, &block)
-      end
-
-      def operation(name, opts = {}, &block)
-        if @operations.keys.include?(name)
-          raise DuplicateOperationException::new(500, "DuplicateOperation", "Operation #{name} is already defined", [])
-        end
-        # Preserve self as local variable to workaround Ruby namespace
-        # weirdness
-        c = self
-        path_generator = Proc.new do |obj|
-          if obj.member?
-            if obj.standard?
-              "#{parent.name}/:#{parent.name.to_s.singularize}/:#{c.name.to_s.singularize}"
-            else
-              "#{parent.name}/:#{parent.name.to_s.singularize}/:#{c.name.to_s.singularize}/#{name}"
-            end
-          else
-            if obj.form?
-              "#{parent.name}/:id/:#{parent.name.to_s.singularize}/#{obj.name}"
-            else
-              "#{parent.name}/:#{parent.name.to_s.singularize}"
-            end
-          end
-        end
-        opts.merge!({
-          :path_generator => path_generator
-        })
-        @operations[name] = Operation.new(self, name, opts, &block)
-      end
-
-      def generate
-        operations.values.reject { |op| op.member }.each { |o| o.generate }
-        operations.values.select { |op| op.member }.each { |o| o.generate }
-        app = ::Sinatra::Application
-        collname = name # Work around Ruby's weird scoping/capture
-        app.send(:define_method, "#{parent.name.to_s}_#{name.to_s.singularize}_url") do |id, subid|
-          api_url_for "#{collname}/#{id}/#{subid}", :full
-        end
-        if index_op = operations[:index]
-          app.send(:define_method, "#{parent.name.to_s}_#{name}_url") do
-            api_url_for index_op.path.gsub(/\/\?$/,''), :full
-          end
-        end
-      end
-
-    end
-
-    def collections
-      @collections ||= {}
-    end
-
-    # Create a new collection. NAME should be the pluralized name of the
-    # collection.
-    #
-    # Adds a helper method #{name}_url which returns the URL to the :index
-    # operation on this collection.
-    def collection(name, &block)
-      raise DuplicateCollectionException if collections[name]
-      collections[name] = Collection.new(name, &block)
-      collections[name].generate
-    end
-
-    def global_collection(name, &block)
-      raise DuplicateCollectionException if collections[name]
-      collections[name] = Collection.new(name, { :global => true }, &block)
-      collections[name].generate
-    end
-
-    # Make sure this collection can be accessed, regardless of whether the
-    # driver supports it or not
-    def global_collection(name, &block)
-      raise DuplicateCollectionException if collections[name]
-      collections[name] = Collection.new(name, :global => true, &block)
-      collections[name].generate
-    end
-  end
-
-  module RabbitHelper
-    def query_url(url, params)
-      return url if params.nil? || params.empty?
-      url + "?#{URI.escape(params.collect{|k,v| "#{k}=#{v}"}.join('&'))}"
-    end
-
-    def entry_points
-      collections.values.select { |coll|
-        coll.global? || driver.has_collection?(coll.name)
-      }.inject([]) do |m, coll|
-        url = api_url_for coll.operations[:index].path, :full
-        m << [ coll.name, url ]
-      end
-    end
-  end
-
-  register Rabbit
-  helpers RabbitHelper
-end
-
-# In Sinatra < 1.2 there was no helper to create OPTIONS route
-unless Sinatra::Base.respond_to? :options
-  configure do
-    class << Sinatra::Base
-      def options(path, opts={}, &block)
-        route 'OPTIONS', path, opts, &block
-      end
-    end
-    Sinatra::Delegator.delegate :options
-  end
-end
diff --git a/server/lib/sinatra/rack_accept.rb b/server/lib/sinatra/rack_accept.rb
index 2ad52c7..e4a0f1f 100644
--- a/server/lib/sinatra/rack_accept.rb
+++ b/server/lib/sinatra/rack_accept.rb
@@ -12,11 +12,8 @@
 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
 
-require 'sinatra/base'
 require 'rack/accept'
 
-use Rack::Accept
-
 module Rack
 
   module RespondTo
@@ -26,7 +23,6 @@ module Rack
     # We need to overide the default render method to supply correct path to the
     # template, since Sinatra is by default looking in the current __FILE__ path
     def self.registered(app)
-      app.helpers Rack::RespondTo::Helpers
       app.class_eval do
         alias :render_without_format :render
         def render(*args, &block)
diff --git a/server/lib/sinatra/rack_cimi.rb b/server/lib/sinatra/rack_cimi.rb
deleted file mode 100644
index 6d5ea78..0000000
--- a/server/lib/sinatra/rack_cimi.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Rack
-  # Automatically sets the X-CIMI-Specification-Version header on all responses.
-  #
-  class CIMI
-
-    def initialize(app, no_cache_control = nil, cache_control = nil)
-      @app = app
-    end
-
-    def call(env)
-      status, headers, body = @app.call(env)
-      headers['X-CIMI-Specification-Version'] = '0.0.66'
-      [status, headers, body]
-    end
-
-  end
-end
-
diff --git a/server/lib/sinatra/rack_matrix_params.rb b/server/lib/sinatra/rack_matrix_params.rb
index 177e745..0d9339b 100644
--- a/server/lib/sinatra/rack_matrix_params.rb
+++ b/server/lib/sinatra/rack_matrix_params.rb
@@ -51,9 +51,7 @@ module Rack
         while param=sub_components.pop do
           if value
             matrix_params[sub_components.first] ||= {}
-            matrix_params[sub_components.first].merge!(
-                                                       param => value
-                                                       )
+            matrix_params[sub_components.first].merge!(param => value)
             value=nil
             next
           else
diff --git a/server/lib/sinatra/rack_runtime.rb b/server/lib/sinatra/rack_runtime.rb
deleted file mode 100644
index dc56fc7..0000000
--- a/server/lib/sinatra/rack_runtime.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (c) 2008 The Committers
-
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-module Rack
-  # Sets an "X-Runtime" response header, indicating the response
-  # time of the request, in seconds
-  #
-  # You can put it right before the application to see the processing
-  # time, or before all the other middlewares to include time for them,
-  # too.
-  class Runtime
-    def initialize(app, name = nil)
-      @app = app
-      @header_name = "X-Runtime"
-      @header_name << "-#{name}" if name
-    end
-
-    def call(env)
-      start_time = Time.now
-      status, headers, body = @app.call(env)
-      request_time = Time.now - start_time
-
-      if !headers.has_key?(@header_name)
-        headers[@header_name] = "%0.6f" % request_time
-      end
-
-      [status, headers, body]
-    end
-  end
-end
-
diff --git a/server/lib/sinatra/rack_syslog.rb b/server/lib/sinatra/rack_syslog.rb
deleted file mode 100644
index 5565179..0000000
--- a/server/lib/sinatra/rack_syslog.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-begin
-  require 'syslog'
-  USE_SYSLOG = true
-rescue LoadError => e
-  USE_SYSLOG = false
-end
-
-require 'sinatra/body_proxy'
-
-class SyslogFile < File
-
-  def initialize
-    @log = USE_SYSLOG ? Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_LOCAL5) : Logger.new(STDOUT)
-  end
-
-  def write(string)
-    @log.warning(string) if string.strip.length > 0
-    return string.chars.count
-  end
-
-  def info(msg)
-    @log.info("%s" % msg)
-  end
-
-  def err(msg)
-    @log.err("%s" % msg)
-  end
-
-  alias :warning :err
-
-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}
-
-    def initialize(app, logger=nil)
-      @app = app
-      @logger = logger || @app.settings.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) do
-        log(env, status, header, began_at)
-      end
-      body.close
-      [status, header, body]
-    end
-
-    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
-      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/lib/sinatra/sinatra_verbose.rb b/server/lib/sinatra/sinatra_verbose.rb
deleted file mode 100644
index c016ec0..0000000
--- a/server/lib/sinatra/sinatra_verbose.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-
-module Sinatra
-  module VerboseLogger
-
-    module Helpers
-
-      def info(message)
-        puts sprintf("\033[1;34m[INFO: #{caller_method_name}]\033[0m: %s", message.inspect)
-      end
-
-      alias :debug :info
-
-      def warn(message)
-        puts sprintf("\033[1;31m[WARN: #{caller_method_name}]\033[0m: %s", message.inspect)
-      end
-
-      private
-
-      def caller_method_name
-        caller(2).first
-      end
-
-    end
-
-    def enable_verbose_logging!
-      disable :logging
-      before {
-        puts sprintf("\n\033[1;29mProcessing %s\033[0m (for %s at #{Time.now}) [%s] [\033[1;29m%s\033[0m]",
-                     request.path_info, request.ip, request.request_method, driver_name)
-        puts "Parameters: #{params.inspect}"
-        if provider=Thread::current[:provider] || ENV['API_PROVIDER']
-          puts "Provider: #{provider}"
-        end
-        puts "Authentication: #{request.env['HTTP_AUTHORIZATION'].split(' ').first}" if request.env['HTTP_AUTHORIZATION']
-        puts "Server: #{request.env['SERVER_SOFTWARE']}"
-        puts "Accept: #{request.env['HTTP_ACCEPT']}"
-        puts
-      }
-      after {
-        puts sprintf("\nCompleted in \033[1;29m%4f\033[0m | %4f | %s | \033[1;36m%s\033[0m | %s\n",
-                     response.header['X-Backend-Runtime'] || 0, response.header['X-Runtime'] || 0, response.status, response.content_type, request.url)
-      }
-    end
-
-    def self.registered(app)
-      app.helpers VerboseLogger::Helpers
-      app.enable_verbose_logging! if ENV['API_VERBOSE']
-    end
-  end
-end
-
-Sinatra::Application.register Sinatra::VerboseLogger
-
-Deltacloud::BaseDriver.class_eval do
-  include Sinatra::VerboseLogger::Helpers
-end
diff --git a/server/lib/sinatra/static_assets.rb b/server/lib/sinatra/static_assets.rb
deleted file mode 100644
index 5233965..0000000
--- a/server/lib/sinatra/static_assets.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-require 'sinatra/url_for'
-
-module Sinatra
-  module StaticAssets
-    module Helpers
-      # In HTML <link> and <img> tags have no end tag.
-      # In XHTML, on the contrary, these tags must be properly closed.
-      #
-      # We can choose the appropriate behaviour with +closed+ option:
-      #
-      #   image_tag "/images/foo.png", :alt => "Foo itself", :closed => true
-      #
-      # The default value of +closed+ option is +false+.
-      #
-      def image_tag(source, options = {})
-        options[:src] = url_for(source)
-        tag("img", options)
-      end
-
-      def stylesheet_link_tag(*sources)
-        list, options = extract_options(sources)
-        list.collect { |source| stylesheet_tag(source, options) }.join("\n")
-      end
-
-      def javascript_script_tag(*sources)
-        list, options = extract_options(sources)
-        list.collect { |source| javascript_tag(source, options) }.join("\n")
-      end
-
-      def link_to(desc, url, options = {})
-        tag("a", options.merge(:href => url_for(url))) do
-          desc
-        end
-      end
-
-      private
-
-      def tag(name, local_options = {})
-        start_tag = "<#{name}#{tag_options(local_options) if local_options}"
-        if block_given?
-          content = yield
-          "#{start_tag}>#{content}</#{name}>"
-        else
-          "#{start_tag}#{"/" if settings.xhtml}>"
-        end
-      end
-
-      def tag_options(options)
-        unless options.empty?
-          attrs = []
-          attrs = options.map { |key, value| %(#{key}="#{Rack::Utils.escape_html(value)}") }
-          " #{attrs.sort * ' '}" unless attrs.empty?
-        end
-      end
-
-      def stylesheet_tag(source, options = {})
-        tag("link", { :type => "text/css",
-            :charset => "utf-8", :media => "screen", :rel => "stylesheet",
-            :href => url_for(source) }.merge(options))
-      end
-
-      def javascript_tag(source, options = {})
-        tag("script", { :type => "text/javascript", :charset => "utf-8",
-            :src => url_for(source) }.merge(options)) do
-            end
-      end
-
-      def extract_options(a)
-        opts = a.last.is_a?(::Hash) ? a.pop : {}
-        [a, opts]
-      end
-
-    end
-
-    def self.registered(app)
-      app.helpers StaticAssets::Helpers
-      app.disable :xhtml
-    end
-  end
-
-  register StaticAssets
-end
diff --git a/server/lib/sinatra/url_for.rb b/server/lib/sinatra/url_for.rb
deleted file mode 100644
index fba6668..0000000
--- a/server/lib/sinatra/url_for.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-#
-# Based on https://github.com/emk/sinatra-url-for/
-# Commit 1df339284203f8f6ed8d
-#
-# Original license:
-# Copyright (C) 2009 Eric Kidd
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the
-# following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-# USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require 'uri'
-
-module Sinatra
-  module UrlForHelper
-
-    def api_url_for(url_fragment, mode=:path_only)
-      matrix_params = ''
-      if request.params['api']
-        matrix_params += ";provider=%s" % request.params['api']['provider'] if request.params['api']['provider']
-        matrix_params += ";driver=%s" % request.params['api']['driver'] if request.params['api']['driver']
-      end
-      url_fragment = "/#{url_fragment}" unless url_fragment =~ /^\// # There is no need to prefix URI with '/'
-      url_for "#{settings.root_url}#{matrix_params}#{url_fragment}", mode
-    end
-
-    # Construct a link to +url_fragment+, which should be given relative to
-    # the base of this Sinatra app.  The mode should be either
-    # <code>:path_only</code>, which will generate an absolute path within
-    # the current domain (the default), or <code>:full</code>, which will
-    # include the site name and port number.  (The latter is typically
-    # necessary for links in RSS feeds.)  Example usage:
-    #
-    #   url_for "/"            # Returns "/myapp/"
-    #   url_for "/foo"         # Returns "/myapp/foo"
-    #   url_for "/foo", :full  # Returns "http://example.com/myapp/foo"
-    #--
-    # See README.rdoc for a list of some of the people who helped me clean
-    # up earlier versions of this code.
-    def url_for url_fragment, mode=:path_only
-      case mode
-      when :path_only
-        base = request.script_name
-      when :full
-        scheme = request.scheme
-        port = request.port
-        request_host = request.host
-        if request.env['HTTP_X_FORWARDED_FOR']
-          scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || scheme
-          port = request.env['HTTP_X_FORWARDED_PORT']
-          request_host = request.env['HTTP_X_FORWARDED_HOST']
-        end
-        if (port.nil? || port == "" ||
-            (scheme == 'http' && port.to_s == '80') ||
-            (scheme == 'https' && port.to_s == '443'))
-          port = ""
-        else
-          port = ":#{port}"
-        end
-        base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
-      else
-        raise TypeError, "Unknown url_for mode #{mode}"
-      end
-      url_escape = URI.escape(url_fragment)
-      # Don't add the base fragment if url_for gets called more than once
-      # per url or the url_fragment passed in is an absolute url
-      if url_escape.match(/^#{base}/) or url_escape.match(/^http/)
-        url_escape
-      else
-        "#{base}#{url_escape}"
-      end
-    end
-  end
-
-
-
-  helpers UrlForHelper
-end
diff --git a/server/views/addresses/show.html.haml b/server/views/addresses/show.html.haml
index b646bf4..ab4b4e2 100644
--- a/server/views/addresses/show.html.haml
+++ b/server/views/addresses/show.html.haml
@@ -13,7 +13,7 @@
     %li
       %div{ :'data-role' => 'controlgroup', :'data-type' => "horizontal" }
         - if @address.associated?
-          =link_to @address.instance_id, instance_url(@address.instance_id)
+          %a{:href => instance_url(@address.instance_id) }=@address.instance_id
           =link_to_action 'Disassociate', disassociate_address_url(@address.id), :post
         - else
           - if driver.respond_to?(:associate_address)
diff --git a/server/views/api/show.html.haml b/server/views/api/show.html.haml
index 265739d..9a40860 100644
--- a/server/views/api/show.html.haml
+++ b/server/views/api/show.html.haml
@@ -3,8 +3,11 @@
 
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview, :'data-inset' => 'true'}
-    - @collections.sort_by { |k| k.to_s }.each do |key|
-      %li= link_to key.to_s.gsub('_', ' ').titlecase, api_url_for(key), :'data-icon' => "arrow-r", :'data-ajax' => false
+
+    - Deltacloud.collections.each do |c|
+      - next unless c.operation(:index).has_capability?
+      %li
+        %a{ :href => api_url_for(c.collection_name),  :'data-icon' => "arrow-r"}=c.collection_name.to_s.gsub('_', ' ').titlecase
 
 - if @providers.size > 1
   %div{ :'data-role' => :footer, :'data-theme' => 'a'}
diff --git a/server/views/error.html.haml b/server/views/error.html.haml
index 4911e28..92897e1 100644
--- a/server/views/error.html.haml
+++ b/server/views/error.html.haml
@@ -2,8 +2,8 @@
 %html
   %head
     %title Deltacloud API #{settings.version}
-    = stylesheet_link_tag '/stylesheets/jquery.mobile-1.0.1.min.css'
-    = stylesheet_link_tag '/stylesheets/new.css'
+    %link{ :charset => "utf-8", :href => "/stylesheets/jquery.mobile-1.0.1.min.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}
+    %link{ :charset => "utf-8", :href => "/stylesheets/new.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}
     %script{:type => "text/javascript", :src => "/javascripts/jquery.min.js" }
     %script{:type => "text/javascript", :src => "/javascripts/application.js" }
     %script{:type => "text/javascript", :src => "/javascripts/jquery.mobile-1.0.1.min.js" }
diff --git a/server/views/instances/new.html.haml b/server/views/instances/new.html.haml
index 2347022..5ca775c 100644
--- a/server/views/instances/new.html.haml
+++ b/server/views/instances/new.html.haml
@@ -21,7 +21,7 @@
   %form{ :action => instances_url, :method => :post, :class => :new_instance, :'data-ajax' => 'false'}
     %input{ :name => :image_id, :type => :hidden, :value => @instance.image_id }/
 
-    - if driver_has_feature?(:user_name)
+    - if driver.class.has_feature?(:instances, :user_name)
       %div{ 'data-role' => :fieldcontain }
         %label{ :for => :name} Instance name:
         %input{ :type => :text, :id => :name, :name => :name, :value => '' }
@@ -29,19 +29,19 @@
     %div{ 'data-role' => :collapsible, 'data-collapsed' => "true"}
       %h3 Additional parameters
 
-      - if driver_has_feature?(:user_data)
+      - if driver.class.has_feature?(:instances, :user_data)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :user_data} Base64 encoded user-data:
           %textarea{ :id => :user_data, :name => :user_data, :value => '' }
           %br/
           %a{ :href => "", :onclick => 'encodeb64();', :'data-ajax' => 'false'} Encode data
 
-      - if driver_has_feature?(:instance_count)
+      - if driver.class.has_feature?(:instances, :instance_count)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :instance_count} # of instances to be launched:
           %input{ :type => :text, :id => :instance_count, :name => :instance_count, :value => '1' }
 
-      - if driver_has_feature?(:authentication_key)
+      - if driver.class.has_feature?(:instances, :authentication_key)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :keyname, :class => 'ui-input-text'} Instance SSH key:
           %select{:name => 'keyname', :'data-native-menu' => "true" }
@@ -49,7 +49,7 @@
             - @keys.each do |key|
               %option{ :value => key.id } #{key.id}
 
-      - if driver_has_feature?(:register_to_load_balancer)
+      - if driver.class.has_feature?(:instances, :register_to_load_balancer)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :load_balancer_id, :class => 'ui-input-text'} Register to loadbalancer:
           %select{:name => 'load_balancer_id', :'data-native-menu' => "true" }
@@ -57,7 +57,7 @@
             - @load_balancers.each do |load_balancer|
               %option{:value => load_balancer.id} #{load_balancer.id}
 
-      - if driver_has_feature?(:firewalls)
+      - if driver.class.has_feature?(:instances, :firewalls)
         %div{ 'data-role' => :fieldcontain }
           %fieldset{ :'data-role' => 'controlgroup'}
             %legend Register to firewall:
diff --git a/server/views/instances/show.xml.haml b/server/views/instances/show.xml.haml
index b2fd5bf..3a62ed3 100644
--- a/server/views/instances/show.xml.haml
+++ b/server/views/instances/show.xml.haml
@@ -45,7 +45,7 @@
     %storage_volumes<
       - @instance.storage_volumes.each do |volume|
         %storage_volume{:href=> storage_volume_url(volume.keys.first), :id => volume.keys.first, :device => volume.values.first}
-  - if driver_has_auth_features?
+  - if driver.class.has_feature?(:authentication_key) or driver.class.has_feature?(:authentication_password)
     %authentication{ :type => driver_auth_feature_name }
       - if @instance.authn_feature_failed?
         %error  #{@instance.authn_error}
diff --git a/server/views/layout.html.haml b/server/views/layout.html.haml
index bef167d..639c618 100644
--- a/server/views/layout.html.haml
+++ b/server/views/layout.html.haml
@@ -2,16 +2,14 @@
 %html
   %head
     %title Deltacloud API #{settings.version}
-    = stylesheet_link_tag '/stylesheets/jquery.mobile-1.0.1.min.css'
-    = stylesheet_link_tag '/stylesheets/new.css'
+    %link{ :charset => "utf-8", :href => "/stylesheets/jquery.mobile-1.0.1.min.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}
+    %link{ :charset => "utf-8", :href => "/stylesheets/new.css", :media => "screen", :rel => "stylesheet", :type => "text/css"}
     %script{:type => "text/javascript", :src => "/javascripts/jquery.min.js" }
     %script{:type => "text/javascript", :src => "/javascripts/application.js" }
     %script{:type => "text/javascript", :src => "/javascripts/jquery.mobile-1.0.1.min.js" }
     :javascript
       $(document).bind("mobileinit", function(){
-          $.mobile.ajaxEnabled = false;
           $.mobile.hashListeningEnabled = false;
-          $.mobile.selectmenu.prototype.options.nativeMenu = false;
       })
   %body
     %div{ 'data-role' => :page }
diff --git a/server/views/root/index.html.haml b/server/views/root/index.html.haml
index c102a59..cc2d36e 100644
--- a/server/views/root/index.html.haml
+++ b/server/views/root/index.html.haml
@@ -1,4 +1,4 @@
 %h1
   Deltacloud:
   = DRIVER.to_s.titlecase
-= link_to 'API', api_url
+%a{ :href => api_url} API
-- 
1.7.10.1


[PATCH core 20/51] Core: Fixed 19 vs 18 backward compatibility issue

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/metrics.rb |    1 +
 server/lib/deltacloud/collections/realms.rb  |    1 +
 server/lib/deltacloud/core_ext/string.rb     |    4 +++
 server/lib/deltacloud/drivers/base_driver.rb |    3 ++-
 server/lib/sinatra.rb                        |    1 +
 tests/mock/step_definitions/api_steps.rb     |   36 +++++++++++++-------------
 tests/mock/support/env.rb                    |   23 ++++++++--------
 7 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/server/lib/deltacloud/collections/metrics.rb b/server/lib/deltacloud/collections/metrics.rb
index acc951d..d13ba38 100644
--- a/server/lib/deltacloud/collections/metrics.rb
+++ b/server/lib/deltacloud/collections/metrics.rb
@@ -15,6 +15,7 @@
 
 module Deltacloud::Collections
   class Metrics < Base
+    check_capability :for => lambda { |m| driver.respond_to? m }
 
     collection :metrics do
       description 'Metrics provide monitoring for the cloud resources'
diff --git a/server/lib/deltacloud/collections/realms.rb b/server/lib/deltacloud/collections/realms.rb
index 3f21625..609a1dd 100644
--- a/server/lib/deltacloud/collections/realms.rb
+++ b/server/lib/deltacloud/collections/realms.rb
@@ -15,6 +15,7 @@
 
 module Deltacloud::Collections
   class Realms < Base
+    check_capability :for => lambda { |m| driver.respond_to? m }
 
     collection :realms do
       description "Within a cloud provider a realm represents a boundary containing resources"
diff --git a/server/lib/deltacloud/core_ext/string.rb b/server/lib/deltacloud/core_ext/string.rb
index 6c04282..abf4a28 100644
--- a/server/lib/deltacloud/core_ext/string.rb
+++ b/server/lib/deltacloud/core_ext/string.rb
@@ -72,4 +72,8 @@ class String
     "#{self[0..(length/2)]}#{end_string}"
   end
 
+  unless "".respond_to? :each
+    alias :each :each_line
+  end
+
 end
diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb
index f3637b7..3d4c75d 100644
--- a/server/lib/deltacloud/drivers/base_driver.rb
+++ b/server/lib/deltacloud/drivers/base_driver.rb
@@ -144,7 +144,8 @@ module Deltacloud
     end
 
     def has_capability?(method)
-      (self.class.instance_methods - self.class.superclass.methods).include? method
+      method = (RUBY_VERSION =~ /^1\.9/) ? method : method.to_s
+      (self.class.instance_methods - self.class.superclass.instance_methods).include? method
     end
 
     ## Capabilities
diff --git a/server/lib/sinatra.rb b/server/lib/sinatra.rb
index 6179d55..13197f5 100644
--- a/server/lib/sinatra.rb
+++ b/server/lib/sinatra.rb
@@ -13,6 +13,7 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+require_relative 'sinatra/body_proxy'
 require_relative 'sinatra/rack_date'
 require_relative 'sinatra/rack_etag'
 require_relative 'sinatra/rack_matrix_params'
diff --git a/tests/mock/step_definitions/api_steps.rb b/tests/mock/step_definitions/api_steps.rb
index 27d1e8f..77c61fb 100644
--- a/tests/mock/step_definitions/api_steps.rb
+++ b/tests/mock/step_definitions/api_steps.rb
@@ -10,11 +10,11 @@ end
 Given /^URI ([\w\/\-_]+) exists in (.+) format$/ do |uri, format|
   @no_header = true
   case format.downcase
-    when 'xml':
+    when 'xml' then
       header 'Accept', 'application/xml;q=9'
-    when 'json'
+    when 'json' then
       header 'Accept', 'application/json;q=9'
-    when 'html'
+    when 'html' then
       header 'Accept', 'application/xml+xhtml;q=9'
   end
   @uri = uri
@@ -55,11 +55,11 @@ Then /^this URI should be available in (.+) format$/ do |formats|
   @no_header = true
   formats.split(',').each do |format|
     case format.downcase
-      when 'xml':
+      when 'xml' then
         header 'Accept', 'application/xml;q=9'
-      when 'json'
+      when 'json' then
         header 'Accept', 'application/json;q=9'
-      when 'html'
+      when 'html' then
         header 'Accept', 'application/xml+xhtml;q=9'
     end
     get @uri, {}
@@ -70,15 +70,15 @@ end
 
 Then /^each (\w+) should have '(.+)' attribute with valid (.+)$/ do |el, attr, t|
   case el
-    when 'link':
+    when 'link' then
       path = '/api/link'
-    when 'image':
+    when 'image' then
       path = '/images/image'
-    when 'instance':
+    when 'instance' then
       path = '/instances/instance'
-    when 'key':
+    when 'key' then
       path = '/keys/key'
-    when 'realm':
+    when 'realm' then
       path = '/realms/realm'
   end
   output_xml.xpath(path).each do |entry_point|
@@ -92,11 +92,11 @@ end
 
 Then /^each ([\w\-]+) should have '(.+)' attribute set to '(.+)'$/ do |el, attr, v|
   case el
-    when 'image':
+    when 'image' then
       path = "/image/images"
-    when 'hardware_profile':
+    when 'hardware_profile' then
       path = "/hardware_profiles/hardware_profile"
-    when 'instance':
+    when 'instance' then
       path = "/instances/instance"
   end
   output_xml.xpath(path).each do |element|
@@ -106,11 +106,11 @@ end
 
 Then /^each ([\w\-]+) should have '(.+)' element set to '(.+)'$/ do |el, child, v|
   case el
-    when 'image':
+    when 'image' then
       path = "/images/image"
-    when 'hardware_profile':
+    when 'hardware_profile' then
       path = "/hardware_profiles/hardware_profile"
-    when 'instance':
+    when 'instance' then
       path = "/instances/instance"
   end
   output_xml.xpath(path).each do |element|
@@ -121,7 +121,7 @@ end
 
 Then /^each ([\w\-]+) should have '(.+)' property set to '(.+)'$/ do |el, property, v|
   case el
-    when 'hardware_profile':
+    when 'hardware_profile' then
       path = "/hardware_profiles/hardware_profile"
   end
   output_xml.xpath(path).each do |element|
diff --git a/tests/mock/support/env.rb b/tests/mock/support/env.rb
index 5f97b89..8b2581f 100644
--- a/tests/mock/support/env.rb
+++ b/tests/mock/support/env.rb
@@ -1,16 +1,13 @@
 require 'rubygems'
 require 'nokogiri'
-
-SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
-$top_srcdir = SERVER_DIR
-$:.unshift File::join($top_srcdir, 'lib')
-Dir.chdir(SERVER_DIR)
-
-ENV['API_DRIVER'] = 'mock'
-ENV.delete('API_VERBOSE')
-load File.join($top_srcdir, 'lib', 'deltacloud', 'server.rb')
-
 require 'rack/test'
+load File.join(File.dirname(__FILE__), '..', '..', '..', 'server', 'lib', 'deltacloud_rack.rb')
+
+Deltacloud::configure do |server|
+  server.root_url '/api'
+  server.version '0.5.0'
+  server.klass 'Deltacloud::API'
+end.require_frontend!
 
 CONFIG = {
   :username => 'mockuser',
@@ -22,5 +19,9 @@ def output_xml
 end
 
 def app
-  Sinatra::Application
+  Rack::URLMap.new(
+    "/" => Deltacloud::API.new,
+    "/stylesheets" =>  Rack::Directory.new( "public/stylesheets" ),
+    "/javascripts" =>  Rack::Directory.new( "public/javascripts" )
+  )
 end
-- 
1.7.10.1


[PATCH core 40/51] * Rakefile (test:cimi): remove useless task

Posted by mf...@redhat.com.
From: David Lutterkort <lu...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Rakefile |    9 ---------
 1 file changed, 9 deletions(-)

diff --git a/server/Rakefile b/server/Rakefile
index 50971f5..c9ef650 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -236,13 +236,4 @@ namespace :test do
       t.warning = false
     }
   end
-
-  desc "Run CIMI frontend tests"
-  Rake::TestTask.new "cimi" do |t|
-    t.test_files = ["tests/cimi/cimi.rb", "tests/cimi/common/*_test.rb"]
-    t.options = "-v -v"
-    t.verbose = true
-    t.warning = false
-  end
-
 end
-- 
1.7.10.1


[PATCH core 04/51] Core: Drivers are now loaded on demand and the 'require "base_driver"' is not longer required in driver

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers.rb                   |   48 +------
 .../lib/deltacloud/drivers/azure/azure_driver.rb   |    4 -
 server/lib/deltacloud/drivers/base_driver.rb       |    7 +-
 .../lib/deltacloud/drivers/condor/condor_driver.rb |    7 -
 server/lib/deltacloud/drivers/ec2/ec2_driver.rb    |   15 +--
 .../drivers/eucalyptus/eucalyptus_driver.rb        |    4 -
 server/lib/deltacloud/drivers/features.rb          |  111 ++++++++++++++++
 .../lib/deltacloud/drivers/gogrid/gogrid_driver.rb |    6 -
 .../lib/deltacloud/drivers/google/google_driver.rb |    3 -
 server/lib/deltacloud/drivers/mock/mock_client.rb  |   11 --
 server/lib/deltacloud/drivers/mock/mock_driver.rb  |   21 +--
 .../drivers/mock/mock_driver_cimi_methods.rb       |  139 --------------------
 .../drivers/opennebula/opennebula_driver.rb        |    4 -
 .../drivers/openstack/openstack_driver.rb          |    6 +-
 .../drivers/rackspace/rackspace_driver.rb          |    9 +-
 .../lib/deltacloud/drivers/rhevm/rhevm_driver.rb   |   17 +--
 .../drivers/rimuhosting/rimuhosting_driver.rb      |    7 +-
 .../drivers/terremark/terremark_driver.rb          |    3 +-
 .../deltacloud/drivers/vsphere/vsphere_driver.rb   |   11 +-
 server/lib/deltacloud/helpers/driver_helper.rb     |    5 +-
 server/lib/deltacloud/models.rb                    |   25 +++-
 server/lib/deltacloud/models/state_machine.rb      |   19 ++-
 22 files changed, 184 insertions(+), 298 deletions(-)
 create mode 100644 server/lib/deltacloud/drivers/features.rb

diff --git a/server/lib/deltacloud/drivers.rb b/server/lib/deltacloud/drivers.rb
index dfc998d..14e7ee0 100644
--- a/server/lib/deltacloud/drivers.rb
+++ b/server/lib/deltacloud/drivers.rb
@@ -13,25 +13,15 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-module Deltacloud
+require_relative 'drivers/exceptions'
+require_relative 'drivers/base_driver'
+require_relative 'drivers/features'
+require 'yaml'
 
+module Deltacloud
   module Drivers
 
-    require 'yaml'
-
-    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_config
+    def self.driver_config
       if Thread::current[:drivers].nil?
         Thread::current[:drivers] = {}
         top_srcdir = File.join(File.dirname(__FILE__), '..', '..')
@@ -42,31 +32,5 @@ module Deltacloud
       Thread::current[:drivers]
     end
 
-    def driver_symbol
-      (Thread.current[:driver] || DRIVER).to_sym
-    end
-
-    def driver_name
-      driver_config[:"#{driver_symbol}"][:name]
-    end
-
-    def driver_class
-      basename = driver_config[:"#{driver_symbol}"][:class] || "#{driver_name}Driver"
-      Deltacloud::Drivers.const_get(driver_name).const_get(basename)
-    end
-
-    def driver_source_name
-      File.join("deltacloud", "drivers", "#{driver_symbol}", "#{driver_symbol}_driver.rb")
-    end
-
-    def driver_mock_source_name
-      return File.join('deltacloud', 'drivers', "#{driver_symbol}",
-		       "#{driver_symbol}_driver.rb") if driver_name.eql? 'Mock'
-    end
-
-    def driver
-      require driver_source_name
-      @driver ||= driver_class.new
-    end
   end
 end
diff --git a/server/lib/deltacloud/drivers/azure/azure_driver.rb b/server/lib/deltacloud/drivers/azure/azure_driver.rb
index 24feeb7..db2b6c6 100644
--- a/server/lib/deltacloud/drivers/azure/azure_driver.rb
+++ b/server/lib/deltacloud/drivers/azure/azure_driver.rb
@@ -15,7 +15,6 @@
 # under the License.
 
 #Windows Azure (WAZ) gem at http://github.com/johnnyhalife/waz-storage
-require 'deltacloud/base_driver'
 require 'waz-blobs'
 
 module Deltacloud
@@ -24,9 +23,6 @@ module Deltacloud
 
 class AzureDriver < Deltacloud::BaseDriver
 
-  def supported_collections; [:buckets]
-  end
-
 #--
 # Buckets
 #--
diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb
index 5fb1a79..f3637b7 100644
--- a/server/lib/deltacloud/drivers/base_driver.rb
+++ b/server/lib/deltacloud/drivers/base_driver.rb
@@ -20,6 +20,11 @@ module Deltacloud
 
     include ExceptionHandler
 
+    STATE_MACHINE_OPTS = {
+      :all_states => [:start, :pending, :running, :stopping, :stopped, :finish],
+      :all_actions => [:create, :reboot, :stop, :start, :destroy]
+    }
+
     def self.driver_name
       name.split('::').last.gsub('Driver', '').downcase
     end
@@ -114,7 +119,7 @@ module Deltacloud
     end
 
     def self.define_instance_states(&block)
-      machine = ::Deltacloud::StateMachine.new(&block)
+      machine = ::Deltacloud::StateMachine.new(STATE_MACHINE_OPTS, &block)
       @instance_state_machine = machine
     end
 
diff --git a/server/lib/deltacloud/drivers/condor/condor_driver.rb b/server/lib/deltacloud/drivers/condor/condor_driver.rb
index f5cb741..b0564f9 100644
--- a/server/lib/deltacloud/drivers/condor/condor_driver.rb
+++ b/server/lib/deltacloud/drivers/condor/condor_driver.rb
@@ -14,9 +14,6 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
-
-
 class Instance
   def self.convert_condor_state(state_id)
     case state_id
@@ -44,10 +41,6 @@ module Deltacloud
         feature :instances, :user_data
         feature :instances, :authentication_password
 
-        def supported_collections
-          DEFAULT_COLLECTIONS - [ :storage_volumes, :storage_snapshots ]
-        end
-
         CONDOR_MAPPER_DIR = ENV['CONDOR_MAPPER_DIR'] || '/var/tmp'
 
         def hardware_profiles(credentials, opts={})
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index 2ebb6c2..f7559a3 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -14,7 +14,6 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'aws'
 
 class Instance
@@ -29,13 +28,8 @@ end
 
 module Deltacloud
   module Drivers
-    module EC2
-      class EC2Driver < Deltacloud::BaseDriver
-
-        def supported_collections
-
-          DEFAULT_COLLECTIONS + [ :keys, :buckets, :load_balancers, :addresses, :firewalls, :metrics ]
-        end
+    module Ec2
+      class Ec2Driver < Deltacloud::BaseDriver
 
         feature :instances, :user_data
         feature :instances, :authentication_key
@@ -444,9 +438,7 @@ module Deltacloud
           safely do
             s3_bucket = s3_client.bucket(opts['bucket'])
             if(opts[:id])
-              s3_key = s3_bucket.key(opts[:id], true)
-              raise "Blob #{opts[:id]} in Bucket #{opts['bucket']} NotFound" unless s3_key.exists?
-              blobs << convert_object(s3_key)
+              blobs << convert_object(s3_bucket.key(opts[:id], true))
             else
               s3_bucket.keys({}, true).each do |s3_object|
                 blobs << convert_object(s3_object)
@@ -502,7 +494,6 @@ module Deltacloud
           blob_meta = {}
           safely do
             the_blob = s3_client.bucket(opts['bucket']).key(opts[:id], true)
-            raise "Blob #{opts[:id]} in Bucket #{opts['bucket']} NotFound" unless the_blob.exists?
             blob_meta = the_blob.meta_headers
           end
         end
diff --git a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
index 8737a27..1872cf3 100644
--- a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
+++ b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
@@ -21,10 +21,6 @@ module Deltacloud
     module Eucalyptus
       class EucalyptusDriver < Ec2::Ec2Driver
 
-        def supported_collections
-          DEFAULT_COLLECTIONS + [ :keys, :buckets, :addresses, :firewalls ]
-        end
-
         feature :instances, :user_data
         feature :instances, :authentication_key
         feature :instances, :firewalls
diff --git a/server/lib/deltacloud/drivers/features.rb b/server/lib/deltacloud/drivers/features.rb
new file mode 100644
index 0000000..01d8656
--- /dev/null
+++ b/server/lib/deltacloud/drivers/features.rb
@@ -0,0 +1,111 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+  module InstanceFeatures
+
+    def self.included(k)
+      current_features = features
+      k.instance_eval do
+        features(&current_features)
+      end
+    end
+
+    def self.features(&block)
+      block_given? ? @features = block : @features || Proc.new{}
+    end
+
+    features do
+
+      feature :user_name, :for => :instances do
+        description "Allow to set user-defined name for the instance"
+        operation :create do
+          param :name, :string, :optional
+        end
+      end
+
+      feature :user_data, :for => :instances do
+        description "Allow to pass user-defined data into the instance"
+        operation :create do
+          param :user_data, :string, :optional
+        end
+      end
+
+      feature :user_iso, :for => :instances do
+        description  "Base64 encoded gzipped ISO file will be accessible as CD-ROM drive in instance"
+        operation :create do
+          param :user_iso, :string, :optional
+        end
+      end
+
+      feature :firewalls, :for => :instances do
+        description "Put instance in one or more firewalls (security groups) on launch"
+        operation :create do
+          param :firewalls, :array, :optional, nil, "Array of firewall ID strings"
+          "Array of firewall (security group) id"
+        end
+      end
+
+      feature :authentication_key, :for => :instances do
+        operation :create do
+          param :keyname, :string,  :optional, [], "Key authentification method"
+        end
+        operation :show do
+        end
+      end
+
+      feature :authentication_password, :for => :instances do
+        operation :create do
+          param :password, :string, :optional
+        end
+      end
+
+      feature :hardware_profiles, :for => :instances do
+        description "Size instances according to changes to a hardware profile"
+        # The parameters are filled in from the hardware profiles
+      end
+
+      feature :register_to_load_balancer, :for => :instances do
+        description "Register instance to load balancer"
+        operation :create do
+          param :load_balancer_id, :string, :optional
+        end
+      end
+
+      feature :instance_count, :for => :instances do
+        description "Number of instances to be launch with at once"
+        operation :create do
+          param :instance_count,  :string,  :optional
+        end
+      end
+
+      feature :attach_snapshot, :for => :instances do
+        description "Attach an snapshot to instance on create"
+        operation :create do
+          param :snapshot_id,  :string,  :optional
+          param :device_name,  :string,  :optional
+        end
+      end
+
+      feature :sandboxing, :for => :instances do
+        description "Allow lanuching sandbox images"
+        operation :create do
+          param :sandbox, :string,  :optional
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
index c6336cd..ee08afe 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
@@ -14,7 +14,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/base_driver'
 require 'deltacloud/drivers/gogrid/gogrid_client'
 
 class Instance
@@ -61,11 +60,6 @@ class GogridDriver < Deltacloud::BaseDriver
     @hardware_profiles
   end
 
-  def supported_collections
-    DEFAULT_COLLECTIONS.reject! { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
-    DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
-  end
-
   def images(credentials, opts=nil)
     imgs = []
     if opts and opts[:id]
diff --git a/server/lib/deltacloud/drivers/google/google_driver.rb b/server/lib/deltacloud/drivers/google/google_driver.rb
index 2ffb5f8..8bc6f25 100644
--- a/server/lib/deltacloud/drivers/google/google_driver.rb
+++ b/server/lib/deltacloud/drivers/google/google_driver.rb
@@ -21,9 +21,6 @@ module Deltacloud
 
 class GoogleDriver < Deltacloud::BaseDriver
 
-  def supported_collections; [:buckets]
-  end
-
   feature :buckets, :bucket_location
 
 #--
diff --git a/server/lib/deltacloud/drivers/mock/mock_client.rb b/server/lib/deltacloud/drivers/mock/mock_client.rb
index 956df44..4c27a66 100644
--- a/server/lib/deltacloud/drivers/mock/mock_client.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_client.rb
@@ -91,17 +91,6 @@ module Deltacloud::Drivers::Mock
       FileUtils.rm(fname) if File::exists?(fname)
     end
 
-    def store_cimi(collection, obj)
-      raise "Why no obj.name?" unless obj.name
-      File::open(cimi_file(collection, obj.name), "w") { |f| f.write(obj.to_json) }
-    end
-
-    def destroy_cimi(collection, id)
-      fname = cimi_file(collection, id)
-      raise "No such object: #{id} in #{collection} collection" unless File::exists?(fname)
-      FileUtils.rm(fname)
-    end
-
     def load_all_cimi(model_name)
         model_files = Dir[File::join(cimi_dir(model_name), "*.json")]
         model_files.map{|f| File.read(f)}
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb
index aaa60ca..cd7534b 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
@@ -14,28 +14,16 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-
 require 'yaml'
 require 'base64'
 require 'etc'
-require 'deltacloud/base_driver'
-require 'deltacloud/drivers/mock/mock_client'
-require 'deltacloud/drivers/mock/mock_driver_cimi_methods'
+require_relative 'mock_client'
+require_relative 'mock_driver_cimi_methods'
 
 module Deltacloud::Drivers::Mock
 
   class MockDriver < Deltacloud::BaseDriver
 
-    # If the provider is set to storage, pretend to be a storage-only
-    # driver
-    def supported_collections
-      if api_provider == 'storage'
-        [:buckets]
-      else
-        DEFAULT_COLLECTIONS + [:buckets, :keys]
-      end
-    end
-
     ( REALMS = [
       Realm.new({
         :id=>'us',
@@ -312,11 +300,6 @@ module Deltacloud::Drivers::Mock
       snapshots
     end
 
-    def destroy_storage_snapshot(credentials, opts={})
-      check_credentials(credentials)
-      @client.destroy(:storage_snapshots, opts[:id])
-    end
-
     def keys(credentials, opts={})
       check_credentials(credentials)
       result = @client.build_all(Key)
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
index 2dec66b..bebc45c 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
@@ -32,49 +32,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def create_network(credentials, opts={})
-      check_credentials(credentials)
-      id = "#{opts[:env].send("networks_url")}/#{opts[:name]}"
-      net_hsh = { "id"=> id,
-                  "name" => opts[:name],
-                  "description" => opts[:description],
-                  "created" => Time.now,
-                  "state" => "STARTED",
-                  "access" => opts[:network_config].access,
-                  "bandwithLimit" => opts[:network_config].bandwidth_limit,
-                  "trafficPriority" => opts[:network_config].traffic_priority,
-                  "maxTrafficDelay" => opts[:network_config].max_traffic_delay,
-                  "maxTrafficLoss" =>opts[:network_config].max_traffic_loss,
-                  "maxTrafficJitter" =>opts[:network_config].max_traffic_jitter,
-                  "routingGroup"=> { "href" => opts[:routing_group].id },
-                  "operations" => [{"rel"=>"edit", "href"=> id},
-                                   {"rel"=>"delete", "href"=> id}]    }
-      network = CIMI::Model::Network.from_json(JSON.generate(net_hsh))
-
-      @client.store_cimi(:network, network)
-      network
-    end
-
-    def delete_network(credentials, id)
-      check_credentials(credentials)
-      @client.destroy_cimi(:network, id)
-    end
-
-    def start_network(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "Network", "STARTED")
-    end
-
-    def stop_network(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "Network", "STOPPED")
-    end
-
-    def suspend_network(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "Network", "SUSPENDED")
-    end
-
     def network_configurations(credentials, opts={})
       check_credentials(credentials)
       if opts[:id].nil?
@@ -130,43 +87,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def create_vsp(credentials, opts={})
-      check_credentials(credentials)
-      id = "#{opts[:env].send("vsps_url")}/#{opts[:name]}"
-      vsp_hash = { "id"    => id,
-                    "name"  => opts[:name],
-                    "description" => opts[:description],
-                    "state" => "STARTED",
-                    "created" => Time.now,
-                    "bandwidthReservation"=>opts[:vsp_config].bandwidth_reservation,
-                    "trafficPriority"=>opts[:vsp_config].traffic_priority,
-                    "maxTrafficDelay"=>opts[:vsp_config].max_traffic_delay,
-                    "maxTrafficLoss"=>opts[:vsp_config].max_traffic_loss,
-                    "maxTrafficJitter"=>opts[:vsp_config].max_traffic_jitter,
-                    "network" => {"href" => opts[:network].id},
-                    "operations" => [{"rel"=>"edit", "href"=> id},
-                                     {"rel"=>"delete", "href"=> id}]
-                   }
-      vsp = CIMI::Model::VSP.from_json(JSON.generate(vsp_hash))
-      @client.store_cimi(:vsp, vsp)
-      vsp
-    end
-
-    def start_vsp(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "VSP", "STARTED")
-    end
-
-    def stop_vsp(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "VSP", "STOPPED")
-    end
-
-    def delete_vsp(credentials, id)
-      check_credentials(credentials)
-      @client.destroy_cimi(:vsp, id)
-    end
-
     def vsp_configurations(credentials, opts={})
       check_credentials(credentials)
       if opts[:id].nil?
@@ -189,56 +109,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def addresses(credentials, opts={})
-      check_credentials(credentials)
-      if opts[:id].nil?
-        addresses = @client.load_all_cimi(:address).map{|addr| CIMI::Model::Address.from_json(addr)}
-        addresses.map{|addr|convert_cimi_mock_urls(:address, addr, opts[:env])}.flatten
-      else
-        address = CIMI::Model::Address.from_json(@client.load_cimi(:address, opts[:id]))
-        convert_cimi_mock_urls(:address, address, opts[:env])
-      end
-    end
-
-    def create_address(credentials, opts={})
-      check_credentials(credentials)
-      id = "#{opts[:env].send("addresses_url")}/#{opts[:name]}"
-      addr_hash = { "id"    => id,
-                    "name"  => opts[:name],
-                    "description" => opts[:description],
-                    "created" => Time.now,
-                    "hostName" => opts[:address_template].hostname,
-                    "allocation" => opts[:address_template].allocation,
-                    "defaultGateway" => opts[:address_template].default_gateway,
-                    "dns" => opts[:address_template].dns,
-                    "macAddress" => opts[:address_template].mac_address,
-                    "protocol" => opts[:address_template].protocol,
-                    "mask" => opts[:address_template].mask,
-                    "network" => {"href" => opts[:address_template].network.href},
-                    "operations" => [{"rel"=>"edit", "href"=> id},
-                                     {"rel"=>"delete", "href"=> id}]
-                   }
-      address = CIMI::Model::Address.from_json(JSON.generate(addr_hash))
-      @client.store_cimi(:address, address)
-      address
-    end
-
-    def delete_address(credentials, id)
-      check_credentials(credentials)
-      @client.destroy_cimi(:address, id)
-    end
-
-    def address_templates(credentials, opts={})
-      check_credentials(credentials)
-      if opts[:id].nil?
-        address_templates = @client.load_all_cimi(:address_template).map{|addr_templ| CIMI::Model::AddressTemplate.from_json(addr_templ)}
-        address_templates.map{|addr_templ|convert_cimi_mock_urls(:address_template, addr_templ, opts[:env])}.flatten
-      else
-        address_template = CIMI::Model::AddressTemplate.from_json(@client.load_cimi(:address_template, opts[:id]))
-        convert_cimi_mock_urls(:address_template, address_template, opts[:env])
-      end
-    end
-
     private
 
     def convert_cimi_mock_urls(model_name, cimi_object, context)
@@ -270,15 +140,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def update_object_state(id, object, new_state)
-      klass = CIMI::Model.const_get("#{object}")
-      symbol = object.to_s.downcase.singularize.intern
-      obj = klass.from_json(@client.load_cimi(symbol, id))
-      obj.state = new_state
-      @client.store_cimi(symbol, obj)
-      obj
-    end
-
   end
 
 end
diff --git a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
index cc05332..2c6203b 100644
--- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
+++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
@@ -27,10 +27,6 @@ module Deltacloud
 
 class OpennebulaDriver < Deltacloud::BaseDriver
 
-  def supported_collections
-    DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
-  end
-
   ######################################################################
   # Hardware profiles
   #####################################################################
diff --git a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
index c9ec95b..12dadef 100644
--- a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
+++ b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
@@ -14,9 +14,9 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'openstack/compute'
 require 'tempfile'
+
 module Deltacloud
   module Drivers
     module Openstack
@@ -27,10 +27,6 @@ module Deltacloud
         feature :instances, :user_files
         feature :images, :user_name
 
-        def supported_collections
-          DEFAULT_COLLECTIONS - [ :storage_snapshots, :storage_volumes  ] #+ [ :buckets ]
-        end
-
         define_instance_states do
           start.to( :pending )          .on( :create )
           pending.to( :running )        .automatically
diff --git a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
index a578180..c8030ad 100644
--- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
+++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
@@ -14,7 +14,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/base_driver'
 require 'cloudfiles'
 require 'cloudservers'
 require 'base64'
@@ -30,10 +29,6 @@ class RackspaceDriver < Deltacloud::BaseDriver
   feature :instances, :user_files
   feature :images, :user_name
 
-  def supported_collections
-    DEFAULT_COLLECTIONS + [ :buckets ] - [ :storage_snapshots, :storage_volumes ]
-  end
-
   def hardware_profiles(credentials, opts = {})
     rs = new_client( credentials )
     results = []
@@ -194,8 +189,8 @@ class RackspaceDriver < Deltacloud::BaseDriver
     start.to( :pending )          .on( :create )
     pending.to( :running )        .automatically
     running.to( :running )        .on( :reboot )
-    running.to( :stopping )       .on( :stop )
-    stopping.to( :stopped )       .automatically
+    running.to( :shutting_down )  .on( :stop )
+    shutting_down.to( :stopped )  .automatically
     stopped.to( :finish )         .automatically
   end
 
diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
index 1c96df7..f138f03 100644
--- a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
+++ b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
@@ -14,27 +14,24 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/base_driver'
 require 'rbovirt'
 
 module Deltacloud
   module Drivers
-    module RHEVM
+    module Rhevm
 
-class RHEVMDriver < Deltacloud::BaseDriver
+class RhevmDriver < Deltacloud::BaseDriver
 
-  def supported_collections
-    DEFAULT_COLLECTIONS - [:storage_snapshots]
-  end
-
-  feature :instances, :user_name do
-    constraint :max_length, 50
+  Sinatra::Rabbit::InstancesCollection.features do
+    feature :user_name, :for => :instances do
+      constrain :max_length, 50
+    end
   end
 
   feature :instances, :user_data
   feature :images, :user_name
 
-  USER_NAME_MAX = feature(:instances, :user_name).constraints[:max_length]
+  USER_NAME_MAX = Sinatra::Rabbit::InstancesCollection.feature(:user_name).constraints[:max_length]
 
   # FIXME: These values are just for ilustration
   # Also I choosed 'SERVER' and 'DESKTOP' names
diff --git a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
index 4c2c3aa..55eec11 100644
--- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
+++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
@@ -16,7 +16,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require "deltacloud/base_driver"
 require "deltacloud/drivers/rimuhosting/rimuhosting_client"
 
 module Deltacloud
@@ -131,9 +130,9 @@ class RimuhostingDriver < Deltacloud::BaseDriver
             :owner_id => "root",
             :instance_profile => InstanceProfile.new("none"),
             :actions => instance_actions_for("RUNNING"),
-            :public_addresses => [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] ) ],
-            :launch_time => inst["billing_info"]["order_date"]["iso_format"]
-    })
+            :public_addresses => [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] )],
+            :launch_time => inst["billing_info"]["order_date"]["iso_format"]}
+                )
   end
 
   define_instance_states do
diff --git a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
index 9cc442c..3260c47 100644
--- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
+++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
@@ -19,8 +19,7 @@
 # https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/d-complete-vcloud-express-api-document.aspx
 #
 # 02 May 2010
-#
-require 'deltacloud/base_driver'
+
 require 'fog'
 require 'excon'
 require 'nokogiri'
diff --git a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
index e16be2f..a6a1e58 100644
--- a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
+++ b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
@@ -14,18 +14,17 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'rbvmomi'
 require 'deltacloud/drivers/vsphere/vsphere_client'
 
-module Deltacloud::Drivers::VSphere
+module Deltacloud::Drivers::Vsphere
 
   MAPPER_STORAGE_ROOT = File::join("/var/tmp", "deltacloud-vsphere-#{ENV["USER"]}")
 
-  class VSphereDriver < Deltacloud::BaseDriver
+  class VsphereDriver < Deltacloud::BaseDriver
 
     include Deltacloud::Drivers::VSphere::Helper
-    include Deltacloud::Drivers::VSphere::FileManager
+    include VSphere::FileManager
 
     # You can use 'user_iso' feature to set 'user_iso' parameter when creating
     # a new instance where this parameter can hold gzipped CDROM iso which will
@@ -34,10 +33,6 @@ module Deltacloud::Drivers::VSphere
     feature :instances, :user_data
     feature :instances, :user_name
 
-    def supported_collections
-      DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
-    end
-
     # There is just one hardware profile where memory is measured using maximum
     # memory available on ESX for virtual machines and CPU using maximum free
     # CPU cores in ESX.
diff --git a/server/lib/deltacloud/helpers/driver_helper.rb b/server/lib/deltacloud/helpers/driver_helper.rb
index f620744..8ae61c0 100644
--- a/server/lib/deltacloud/helpers/driver_helper.rb
+++ b/server/lib/deltacloud/helpers/driver_helper.rb
@@ -47,8 +47,9 @@ module Deltacloud::Helpers
       begin
         require_relative driver_source_name
         driver_class
-      rescue LoadError
-        raise "[ERROR] The driver '#{driver_name}' is unknown or not installed (#{driver_source_name})"
+      rescue LoadError => e
+        raise "[ERROR] The driver '#{driver_name}' is unknown or not installed (#{driver_source_name})\n" +
+          "\n#{e.message}\n"
       end
     end
 
diff --git a/server/lib/deltacloud/models.rb b/server/lib/deltacloud/models.rb
index 099afda..e6020e6 100644
--- a/server/lib/deltacloud/models.rb
+++ b/server/lib/deltacloud/models.rb
@@ -14,10 +14,21 @@
 # under the License.
 
 require_relative 'models/base_model'
-
-# Include all models
-
-Dir[File.join(File::dirname(__FILE__), "models", "*.rb")].each do |model|
-  next if model =~ /base_model\.rb$/
-  require model
-end
+require_relative 'models/address'
+require_relative 'models/blob'
+require_relative 'models/bucket'
+require_relative 'models/firewall'
+require_relative 'models/firewall_rule'
+require_relative 'models/hardware_profile'
+require_relative 'models/image'
+require_relative 'models/instance'
+require_relative 'models/instance_address'
+require_relative 'models/instance_profile'
+require_relative 'models/key'
+require_relative 'models/load_balancer'
+require_relative 'models/metric'
+require_relative 'models/provider'
+require_relative 'models/realm'
+require_relative 'models/state_machine'
+require_relative 'models/storage_snapshot'
+require_relative 'models/storage_volume'
diff --git a/server/lib/deltacloud/models/state_machine.rb b/server/lib/deltacloud/models/state_machine.rb
index 19fb9f2..cbdaf4a 100644
--- a/server/lib/deltacloud/models/state_machine.rb
+++ b/server/lib/deltacloud/models/state_machine.rb
@@ -18,7 +18,10 @@ module Deltacloud
   class StateMachine
 
     attr_reader :states
-    def initialize(&block)
+
+    def initialize(opts={}, &block)
+      @all_states = opts[:all_states]
+      @all_actions = opts[:all_actions]
       @states  = []
       instance_eval &block if block
     end
@@ -32,6 +35,9 @@ module Deltacloud
     end
 
     def state(name)
+      unless valid_state_name?(name)
+        raise "State '#{name}' not in list of allowed states"
+      end
       state = @states.find{|e| e.name == name.to_sym}
       if ( state.nil? )
         state = State.new( self, name.to_sym )
@@ -40,6 +46,14 @@ module Deltacloud
       state
     end
 
+    def valid_state_name?(name)
+      @all_states.nil? || @all_states.include?(name.to_sym)
+    end
+
+    def valid_action_name?(name)
+      @all_actions.nil? || @all_actions.include?(name.to_sym)
+    end
+
     def method_missing(sym,*args)
       return state( sym ) if ( args.empty? )
       super( sym, *args )
@@ -90,6 +104,9 @@ module Deltacloud
       end
 
       def on(action)
+        unless @machine.valid_action_name?(action)
+          raise "Action '#{action}' not in list of allowed actions"
+        end
         @action = action
       end
 
-- 
1.7.10.1


[PATCH core 11/51] Core: Storage volumes should always show the :name attribute

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/views/storage_volumes/show.html.haml |    1 +
 server/views/storage_volumes/show.xml.haml  |    5 ++---
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/server/views/storage_volumes/show.html.haml b/server/views/storage_volumes/show.html.haml
index 600e6a4..31a0833 100644
--- a/server/views/storage_volumes/show.html.haml
+++ b/server/views/storage_volumes/show.html.haml
@@ -4,6 +4,7 @@
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-divider-theme' => 'd'}
     %li{ :'data-role' => 'list-divider'} Name
+    %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id
     %li
       %p{ :'data-role' => 'fieldcontain'}=(@storage_volume.name ? @storage_volume.name : @storage_volume.id)
     %li{ :'data-role' => 'list-divider'} Created
diff --git a/server/views/storage_volumes/show.xml.haml b/server/views/storage_volumes/show.xml.haml
index 440609b..f9f5f25 100644
--- a/server/views/storage_volumes/show.xml.haml
+++ b/server/views/storage_volumes/show.xml.haml
@@ -9,9 +9,8 @@
   - if @storage_volume.kind
     %kind<
       = @storage_volume.kind
-  - if @storage_volume.name
-    %name<
-      = @storage_volume.name
+  %name<
+    = @storage_volume.name || @storage_volume.id
   - if @storage_volume.device
     %device<
       = @storage_volume.device
-- 
1.7.10.1


[PATCH core 16/51] Core: Fixed the respond_to extension to return XML when no media-type

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/sinatra/rack_accept.rb |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/server/lib/sinatra/rack_accept.rb b/server/lib/sinatra/rack_accept.rb
index e4a0f1f..4286e93 100644
--- a/server/lib/sinatra/rack_accept.rb
+++ b/server/lib/sinatra/rack_accept.rb
@@ -79,9 +79,16 @@ module Rack
           @media_type ||= accepting_formats.to_a.sort { |a,b| a[1]<=>b[1] }.reverse.select do |format, priority|
             wants.keys.include?(format) == true
           end.first
+          if @media_type and @media_type.kind_of? Symbol
+            @media_type = [ @media_type ]
+          end
           if @media_type and @media_type[0]
             @media_type = @media_type[0]
-            headers 'Content-Type' => Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type][:return]
+            if  Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type]
+              headers 'Content-Type' => Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type][:return]
+            else
+              headers 'Content-Type' => 'application/xml'
+            end
             wants[@media_type.to_sym].call if wants[@media_type.to_sym]
           else
             headers 'Content-Type' => nil
-- 
1.7.10.1


[PATCH core 17/51] Core: Replaced Test/Unit based tests for Mock with new minitest

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Rakefile                                    |   42 +-
 .../deltacloud/drivers/mock/data/keys/test-key.yml |   28 +
 server/tests/drivers/mock/api_test.rb              |  210 ++++----
 server/tests/drivers/mock/buckets_test.rb          |  192 +++++++
 server/tests/drivers/mock/common.rb                |   58 +++
 server/tests/drivers/mock/drivers_test.rb          |  120 +++++
 .../tests/drivers/mock/hardware_profiles_test.rb   |  297 +++++++----
 server/tests/drivers/mock/images_test.rb           |  268 ++++++----
 server/tests/drivers/mock/instance_states_test.rb  |   67 ---
 server/tests/drivers/mock/instances_test.rb        |  545 ++++++++++++--------
 server/tests/drivers/mock/keys_test.rb             |  158 ++++++
 server/tests/drivers/mock/realms_test.rb           |  180 ++++---
 server/tests/drivers/mock/setup.rb                 |    3 -
 .../tests/drivers/mock/storage_snapshots_test.rb   |  111 ++++
 server/tests/drivers/mock/storage_volumes_test.rb  |  119 +++++
 server/tests/drivers/mock/url_for_test.rb          |   67 ---
 16 files changed, 1684 insertions(+), 781 deletions(-)
 create mode 100644 server/lib/deltacloud/drivers/mock/data/keys/test-key.yml
 create mode 100644 server/tests/drivers/mock/buckets_test.rb
 create mode 100644 server/tests/drivers/mock/common.rb
 create mode 100644 server/tests/drivers/mock/drivers_test.rb
 delete mode 100644 server/tests/drivers/mock/instance_states_test.rb
 create mode 100644 server/tests/drivers/mock/keys_test.rb
 delete mode 100644 server/tests/drivers/mock/setup.rb
 create mode 100644 server/tests/drivers/mock/storage_snapshots_test.rb
 create mode 100644 server/tests/drivers/mock/storage_volumes_test.rb
 delete mode 100644 server/tests/drivers/mock/url_for_test.rb

diff --git a/server/Rakefile b/server/Rakefile
index 5d205ce..50971f5 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -71,26 +71,6 @@ begin
 rescue LoadError
 end
 
-namespace :test do
-  %w(mock rackspace rhevm openstack google fgcp).each do |driver|
-    desc "Run #{driver} unit tests"
-    Rake::TestTask.new(driver) { |t|
-      t.test_files = ['tests/common.rb', "tests/drivers/#{driver}/setup.rb"] + FileList.new("tests/drivers/#{driver}/*_test.rb") + FileList.new('tests/rabbit_test.rb')
-      t.options = "-v -v"
-      t.verbose = true
-      t.warning = false
-    }
-  end
-
-  desc "Run CIMI frontend tests"
-  Rake::TestTask.new "cimi" do |t|
-    t.test_files = ["tests/cimi/cimi.rb", "tests/cimi/common/*_test.rb"]
-    t.options = "-v -v"
-    t.verbose = true
-    t.warning = false
-  end
-
-end
 
 desc "Call our Test::Unit suite"
 task :test do
@@ -244,3 +224,25 @@ namespace :rabbit do
 
 end
 
+namespace :test do
+
+  %w(mock rackspace rhevm openstack google fgcp).each do |driver|
+    desc "Run #{driver} unit tests"
+    Rake::TestTask.new(driver) { |t|
+      Rake::Task["mock:fixtures:reset"].invoke
+      t.test_files = ['tests/drivers/'+driver+'/common.rb'] + FileList.new("tests/drivers/#{driver}/*_test.rb")
+      t.options = "-v -v"
+      t.verbose = true
+      t.warning = false
+    }
+  end
+
+  desc "Run CIMI frontend tests"
+  Rake::TestTask.new "cimi" do |t|
+    t.test_files = ["tests/cimi/cimi.rb", "tests/cimi/common/*_test.rb"]
+    t.options = "-v -v"
+    t.verbose = true
+    t.warning = false
+  end
+
+end
diff --git a/server/lib/deltacloud/drivers/mock/data/keys/test-key.yml b/server/lib/deltacloud/drivers/mock/data/keys/test-key.yml
new file mode 100644
index 0000000..a643917
--- /dev/null
+++ b/server/lib/deltacloud/drivers/mock/data/keys/test-key.yml
@@ -0,0 +1,28 @@
+--- 
+:credential_type: :key
+:fingerprint: 5e:ce:b6:dc:59:3b:5c:93:f8:2e:9d:20:ce:60:ca:f5:0b:8a:66:93
+:pem_rsa_key: |-
+  -----BEGIN RSA PRIVATE KEY-----
+  P9mRXOY7p2SmMzTGA6dwKxUp1NB8LNCIJ7sMGgAljsf=ToAi9qn9myx0EQJkE8FZ8FigUIMHS/T
+  8EwP7Ayjztb8dczbC6sb/Ep2UWcegNUVHimyHstaEaO/3dCaFwLJ/kw=laAfLQAVj4sIr8EHDTg
+  /BFkgmwTAYlS/ybkEfO9J7AJlY6/agwYzDWp+VGAD9rMsl2EkkbkWdoTX4Aob9RqyHaFi2m1AAw
+  2nhhqYpa1W4H=PJvyBcsXT3JynowSI8rTvo41oVwgSzv7YofGP0yV7BePm5pXZUUP2ZMByxbAUv
+  jvYRN/cMHbC6RW1ezR3uehCKdKFRXLTkoivoGj4ugrKgOwQP0HWI2orx/NW+6vYBxyCKiTJPZcK
+  x4BlRrlgvPST/7eaFv7/5Pqc3jWcp+bRC0qyYqQT9iq3gGNoc4ABFTI7zCeZ3p9tK8oje5fWo5m
+  54P32hVGeBjfqT/MrEYbY5gbJU6LejCj7x6Ozlp4iHQtrYNhiZ0iP0W3nRhVFQHamKx9aoBXyeg
+  LLGxBOr+TfaeeBXRkXiaMuWoyPSzUQwWmaJhm0sjHf7e/iKiUggZkOHQ/eF9MWI4M+4wvyepfS0
+  5vl2Ql/2rXv+Mx+c4cx1fjBhRrMPcGKmHGjNMjPyamTrlqueFRJYP45AYABP2U2AsNxoPfEG0qu
+  ki3DJOeC5x/03nODd=hQLzfdiQ3Yyt0GMw1EQN96cPaRtnjr3U4/ngxt0Fi6o7Z8E2+Uh5t4n8D
+  h0exXCOlOi9BDsJJz677mga/=5Sin/4Cw8=D8O1FHrWoA4ZQbWFE71F=/29PM90RHJf2bjgk2WF
+  piltKwVfGAxPOTcpmf=J+V3NHgT/EawMPHuEmwgNvx6smDBUgJaw0QYX/XG5xuiQ7HTkffJN6Cm
+  6D4WCJPZUvO1r+v=T9v7Qu4j9ue/l2WwVZuvQsVD67jpzq2R72EHna6rcwwyMcdAlwikP9nzJIL
+  Ale7hQAWHIEeAvAxtwxEMSfTkuLQcD=i0ORysmInDxdORw4ue2YThj2Id/jmUy6IiEqMYeVpiRq
+  6spq2ukt=+HHn6aBcYWbsD=e8/wOk0X0=ixZ0HF+xqYgsiiAk==rA4QEgrf+5djbIRZk1wegeIO
+  po/HZdF4qk32cKBjrrel2AzxfZeGxWNX7ObAE4HACXi3eSdcnm1fIHsoSC+1eDqFkfAIve3Dj/a
+  afZxrda6zzp3g6IPcHAqleCn7XNcS0v5tk4Fag8Wr5Wq7IipRfixAs+GESGiyugeRvZWN2mtDOL
+  CGHGGAbpvplw2vjdryVyj7P6bVcwLNgl0t1ufZBaGRBpyontJ1/UQQMew7e2lW=EZr/GxHke8HN
+  X5vIw9ssx8=LL00fxAuX9SRdcrtVyTYGXORXe9NnldXjBXmLPgwqJAjoBTjTBQxzrQOtdla=/yw
+  MsDlFWumPz1HAFw7R5zS2VCHrwkLDm=h7k3y+fUvYOx6IYf+MmevANuJT+2qY6s/ilTBNDYq6jJ
+  8LYpsBo4XpQm1ZleFCIyRldHfmaC5EMxkVQVqCV7X9I6JgzDEetUre25LQTpDa31M=ucVHNWlT+
+  6rjiLETNeMTWGcuIkLPe/PElmp4llKeFi6g2=E2AKeSDzNycr5eXHEnBuKfEnENXXo6n-----END RSA PRIVATE KEY-----
+:id: test-key
diff --git a/server/tests/drivers/mock/api_test.rb b/server/tests/drivers/mock/api_test.rb
index cfb0921..3308365 100644
--- a/server/tests/drivers/mock/api_test.rb
+++ b/server/tests/drivers/mock/api_test.rb
@@ -1,133 +1,115 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class ApiTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
+describe 'Deltacloud API' do
+  include Deltacloud::Test
 
-    def test_it_returns_entry_points
-      get_auth_url '/api'
-      (last_xml_response/'/api/link').length.should > 0
-    end
+  it 'return HTTP_OK when accessing API entrypoint' do
+    get API_ROOT_URL
+    last_response.status.must_equal 200
+  end
 
-    def test_it_has_correct_attributes_set
-      get_auth_url '/api'
-      (last_xml_response/'/api/link').each do |link|
-        link.attributes.keys.sort.should == [ 'href', 'rel' ]
-      end
-    end
+  it 'advertise the current driver in API entrypoint' do
+    get API_ROOT_URL
+    xml_response.root[:driver].must_equal ENV['API_DRIVER']
+  end
 
-    def test_it_responses_to_html
-      get_url '/api', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-    end
+  it 'advertise the current API version in API entrypoint' do
+    get API_ROOT_URL
+    xml_response.root[:version].must_equal API_VERSION
+  end
 
-    def test_it_responses_to_json
-      get_url '/api', {}, { :format => :json }
-      last_response.status.should == 200
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['api'].class.should == Hash
-    end
+  it 'advertise the current API version in HTTP headers' do
+    get API_ROOT_URL
+    last_response.headers['Server'].must_equal "Apache-Deltacloud/#{API_VERSION}"
+  end
 
-    def test_it_switches_drivers
-      with_provider("") do
-        get_auth_url '/api'
-        (last_xml_response/"api/link[rel = 'instances']").first.should_not == nil
-      end
-
-      # Switch to storage-only mock driver
-      with_provider("storage") do
-        get_auth_url '/api'
-        (last_xml_response/"api/link[rel = 'instances']").first.should == nil
-      end
-    end
+  it 'must include the ETag in HTTP headers' do
+    get API_ROOT_URL
+    last_response.headers['ETag'].wont_be_nil
+  end
 
-    def test_it_handles_unsupported_collections
-      get_auth_url '/api/no_such_collection'
-      last_response.status.should == 404
+  it 'advertise collections in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link').wont_be_empty
+  end
 
-      with_provider("storage") do
-        get_auth_url '/api/instances'
-        last_response.status.should == 403
-      end
+  it 'include the :href and :rel attribute for each collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link').each do |collection|
+      collection[:href].wont_be_nil
+      collection[:rel].wont_be_nil
     end
+  end
 
-    def test_it_allows_accessing_docs
-      get_url '/api/docs/instances'
-      last_response.status.should == 200
-
-      with_provider("storage") do
-        get_url '/api/docs/instances'
-        last_response.status.should == 403
-      end
+  it 'uses the absolute URI in the :href attribute for each collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link').each do |collection|
+      collection[:href].must_match /^http/
     end
+  end
 
-    def test_it_respond_to_head
-      head '/api/instances'
-      last_response.headers['Allow'].should_not == nil
-      last_response.headers['Allow'].split(',').include?('HEAD').should == true
-    end
+  it 'advertise features for some collections in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link/feature').wont_be_empty
+  end
 
-    def test_it_expose_available_drivers
-      get_auth_url '/api/drivers'
-      last_response.status.should == 200
-      (last_xml_response/"drivers").length.should > 0
-      (last_xml_response/'drivers/driver').length.should > 0
-      (last_xml_response/"drivers/driver[@id = 'mock']").length.should == 1
+  it 'advertise the name of the feature for some collections in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link/feature').each do |f|
+      f[:name].wont_be_nil
     end
+  end
 
-    def test_it_expose_ec2_driver_entrypoints
-      get_auth_url '/api/drivers'
-      last_response.status.should == 200
-      ec2 = (last_xml_response/'drivers/driver[@id=ec2]').first
-      (ec2/"provider").length.should > 0
-      (ec2/"provider[@id = 'eu-west-1']").length.should == 1
-      get_auth_url ec2[:href]
-      eu_west = (last_xml_response/"provider[@id = 'eu-west-1']").first
-      (eu_west/"entrypoint").length.should > 0
-      (eu_west/"entrypoint[@kind = 'ec2']").length.should == 1
-    end
+  it 'must change the media type from XML to JSON using Accept headers' do
+    header 'Accept', 'application/json'
+    get API_ROOT_URL
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
 
-    def test_it_supports_matrix_params
-      get_auth_url "/api;driver=ec2"
-      last_response.status.should == 200
-      (last_xml_response/'api').first[:driver].should == 'ec2'
-      get_auth_url "/api;driver=mock"
-      (last_xml_response/'api').first[:driver].should == 'mock'
-      get_auth_url "/api;driver=ec2/hardware_profiles"
-      (last_xml_response/'hardware_profiles/hardware_profile/@id').map {|n| n.to_s}.include?('m1.small').should == true
-      last_response.status.should == 200
-    end
+  it 'must change the media type to JSON using the "?format" parameter in URL' do
+    get API_ROOT_URL, { :format => 'json' }
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
 
-    def test_it_change_features_after_driver_change
-      get_auth_url "/api;driver=ec2"
-      (last_xml_response/'api/link[@rel="instances"]/feature[@name="user_name"]').first.should == nil
-      (last_xml_response/'api/link[@rel="instances"]/feature[@name="user_data"]').first.should_not == nil
-      get_auth_url "/api;driver=mock"
-      (last_xml_response/'api/link[@rel="instances"]/feature[@name="user_name"]').first.should_not == nil
-      (last_xml_response/'api/link[@rel="instances"]/feature[@name="firewalls"]').first.should == nil
-    end
+  it 'must change the driver when using X-Deltacloud-Driver HTTP header' do
+    header 'X-Deltacloud-Driver', 'ec2'
+    get API_ROOT_URL
+    xml_response.root[:driver].must_equal 'ec2'
+    header 'X-Deltacloud-Driver', 'mock'
+    get API_ROOT_URL
+    xml_response.root[:driver].must_equal 'mock'
+  end
 
+  it 'must change the features when driver is swapped using HTTP headers' do
+    header 'X-Deltacloud-Driver', 'ec2'
+    get API_ROOT_URL
+    # The 'user_name' feature is not supported currently for the EC2 driver
+    (xml_response/'api/link/feature').map { |f| f[:name] }.wont_include 'user_name'
+    header 'X-Deltacloud-Driver', 'mock'
+    get API_ROOT_URL
+    # But it's supported in Mock driver
+    (xml_response/'api/link/feature').map { |f| f[:name] }.must_include 'user_name'
   end
+
+  it 'must re-validate the driver credentials when using "?force_auth" parameter in URL' do
+    get API_ROOT_URL, { :force_auth => '1' }
+    last_response.status.must_equal 401
+    auth_as_mock
+    get API_ROOT_URL, { :force_auth => '1' }
+    last_response.status.must_equal 200
+  end
+
+  it 'must change the API PROVIDER using the /api;provider matrix parameter in URI' do
+    get API_ROOT_URL + ';provider=test1'
+    xml_response.root[:provider].wont_be_nil
+    xml_response.root[:provider].must_equal 'test1'
+    get API_ROOT_URL + ';provider=test2'
+    xml_response.root[:provider].must_equal 'test2'
+  end
+
+  it 'must change the API DRIVER using the /api;driver matrix parameter in URI' do
+    get API_ROOT_URL + ';driver=ec2'
+    xml_response.root[:driver].must_equal 'ec2'
+    get API_ROOT_URL + ';driver=mock'
+    xml_response.root[:driver].must_equal 'mock'
+  end
+
 end
diff --git a/server/tests/drivers/mock/buckets_test.rb b/server/tests/drivers/mock/buckets_test.rb
new file mode 100644
index 0000000..f98ad24
--- /dev/null
+++ b/server/tests/drivers/mock/buckets_test.rb
@@ -0,0 +1,192 @@
+describe 'Deltacloud API buckets' do
+  include Deltacloud::Test
+
+  it 'must advertise have the buckets collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=buckets]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "bucket" collection' do
+    get collection_url(:buckets)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :buckets collection with authentication' do
+    auth_as_mock
+    get collection_url(:buckets)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:buckets)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:buckets)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "buckets" element on top level' do
+    auth_as_mock
+    get collection_url(:buckets)
+    xml_response.root.name.must_equal 'buckets'
+  end
+
+  it 'must have some "bucket" elements inside "buckets"' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each bucket in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "bucket" element in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the bucket' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:buckets) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each bucket in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      (r/'name').wont_be_nil
+    end
+  end
+
+  it 'must have the "state" element defined for each bucket in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      (r/'state').wont_be_nil
+    end
+  end
+
+  it 'must return the full "bucket" when following the URL in bucket element' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the bucket and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "size" element for the bucket and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'size').wont_be_empty
+      (xml_response/'size').first.text.must_equal((r/'size').first.text)
+    end
+  end
+
+  it 'must have the "blob" elements for the bucket and it should match with the ones in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'bucket/blob').wont_be_empty
+      (xml_response/'bucket/blob').each do |b|
+        b[:id].wont_be_nil
+        b[:href].wont_be_nil
+        b[:href].must_match /^http/
+        b[:href].must_match /#{r[:id]}\/#{b[:id]}$/
+      end
+    end
+  end
+
+  it 'must have the "blob" elements for the bucket and it should match with the ones in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'bucket/blob').wont_be_empty
+      (xml_response/'bucket/blob').each do |b|
+        b[:id].wont_be_nil
+        b[:href].wont_be_nil
+        b[:href].must_match /^http/
+        b[:href].must_match /#{r[:id]}\/#{b[:id]}$/
+      end
+    end
+  end
+
+  it 'must allow to get all blobs details and the details should be set correctly' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'bucket/blob').each do |b|
+        get collection_url(:buckets) + '/' + r[:id] + '/' + b[:id]
+        xml_response.root.name.must_equal 'blob'
+        xml_response.root[:id].must_equal b[:id]
+        (xml_response/'bucket').wont_be_empty
+        (xml_response/'bucket').size.must_equal 1
+        (xml_response/'bucket').first[:id].wont_be_nil
+        (xml_response/'bucket').first[:href].wont_be_nil
+        (xml_response/'content_length').wont_be_empty
+        (xml_response/'content_length').size.must_equal 1
+        (xml_response/'content_length').first.text.must_match /^(\d+)$/
+        (xml_response/'content_type').wont_be_empty
+        (xml_response/'content_type').size.must_equal 1
+        (xml_response/'content_type').first.text.wont_be_empty
+        (xml_response/'last_modified').wont_be_empty
+        (xml_response/'last_modified').size.must_equal 1
+        (xml_response/'last_modified').first.text.wont_be_empty
+        (xml_response/'content').wont_be_empty
+        (xml_response/'content').size.must_equal 1
+        (xml_response/'content').first[:rel].wont_be_nil
+        (xml_response/'content').first[:rel].must_equal 'blob_content'
+        (xml_response/'content').first[:href].wont_be_nil
+        (xml_response/'content').first[:href].must_match /^http/
+        (xml_response/'content').first[:href].must_match /\/content$/
+      end
+    end
+  end
+
+end
diff --git a/server/tests/drivers/mock/common.rb b/server/tests/drivers/mock/common.rb
new file mode 100644
index 0000000..08650a3
--- /dev/null
+++ b/server/tests/drivers/mock/common.rb
@@ -0,0 +1,58 @@
+unless Kernel.respond_to?(:require_relative)
+  module Kernel
+    def require_relative(path)
+      require File.join(File.dirname(caller[0]), path.to_str)
+    end
+  end
+end
+
+API_ROOT_URL = "/api" unless defined?(API_ROOT_URL)
+API_VERSION = "1.0.0" unless defined?(API_VERSION)
+ENV['API_DRIVER'] ||= 'mock'
+
+ENV['API_USERNAME'] ||= 'mockuser'
+ENV['API_PASSWORD'] ||= 'mockpassword'
+
+require_relative '../../../lib/deltacloud/server.rb'
+
+require 'minitest/autorun'
+require 'rack/test'
+require 'nokogiri'
+require 'json'
+
+require 'pp'
+
+module Deltacloud
+  module Test
+    include Rack::Test::Methods
+
+    def included?(sub)
+      sub.class_eval do
+        before do
+          header 'Accept', 'application/xml'
+        end
+      end
+    end
+
+    def xml_response
+      Nokogiri::XML(last_response.body)
+    end
+
+    def auth_as_mock
+      authorize ENV['API_USERNAME'], ENV['API_PASSWORD']
+    end
+
+    def collection_url(collection)
+      [API_ROOT_URL, collection.to_s].join('/')
+    end
+
+    def app
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
+    end
+  end
+end
diff --git a/server/tests/drivers/mock/drivers_test.rb b/server/tests/drivers/mock/drivers_test.rb
new file mode 100644
index 0000000..41c2e66
--- /dev/null
+++ b/server/tests/drivers/mock/drivers_test.rb
@@ -0,0 +1,120 @@
+describe 'Deltacloud API drivers' do
+  include Deltacloud::Test
+
+  it 'must advertise have the drivers collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=drivers]').wont_be_empty
+  end
+
+  it 'must not require authentication to access the "driver" collection' do
+    get collection_url(:drivers)
+    last_response.status.must_equal 200
+  end
+
+  it 'should respond with HTTP_OK when accessing the :drivers collection with authentication' do
+    get collection_url(:drivers)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    header 'Accept', 'application/json'
+    get collection_url(:drivers)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    get collection_url(:drivers)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "drivers" element on top level' do
+    get collection_url(:drivers)
+    xml_response.root.name.must_equal 'drivers'
+  end
+
+  it 'must have some "driver" elements inside "drivers"' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each driver in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "driver" element in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the driver' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    options collection_url(:drivers) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each driver in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      (r/'name').wont_be_nil
+    end
+  end
+
+
+  it 'must return the full "driver" when following the URL in driver element' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      get collection_url(:drivers) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the driver and it should match with the one in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      get collection_url(:drivers) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'should advertise available providers for some drivers' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver/provider').each do |p|
+      p[:id].wont_be_nil
+    end
+  end
+
+  it 'should expose entrypoints for each provider if driver has providers defined' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver/provider').each do |p|
+      get collection_url(:drivers) + '/' + p.parent[:id]
+      (xml_response/"driver/provider[@id=#{p[:id]}]").wont_be_empty
+      (xml_response/"driver/provider[@id=#{p[:id]}]").size.must_equal 1
+      (xml_response/"driver/provider[@id=#{p[:id]}]/entrypoint").wont_be_empty
+      (xml_response/"driver/provider[@id=#{p[:id]}]/entrypoint").each do |e|
+        e[:kind].wont_be_nil
+        e.text.wont_be_empty
+      end
+    end
+  end
+
+end
diff --git a/server/tests/drivers/mock/hardware_profiles_test.rb b/server/tests/drivers/mock/hardware_profiles_test.rb
index 47f7eb3..3dad5a8 100644
--- a/server/tests/drivers/mock/hardware_profiles_test.rb
+++ b/server/tests/drivers/mock/hardware_profiles_test.rb
@@ -1,134 +1,221 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class HardwareProfilesTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
-
-    def test_it_returns_hardware_profiles
-      get_url '/api/hardware_profiles'
-      (last_xml_response/'hardware_profiles/hardware_profile').length.should > 0
-    end
-
-    def test_it_has_correct_attributes_set
-      get_auth_url '/api/hardware_profiles'
-      (last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
-        profile.attributes.keys.sort.should == [ 'href', 'id' ]
-      end
+describe 'Deltacloud API Hardware Profiles' do
+  include Deltacloud::Test
+
+  it 'must advertise have the hardware_profiles collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=hardware_profiles]').wont_be_empty
+  end
+
+  it 'should respond with HTTP_OK when accessing the :hardware_profiles collection with authentication' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:hardware_profiles)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "hardware_profiles" element on top level' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    xml_response.root.name.must_equal 'hardware_profiles'
+  end
+
+  it 'must have some "hardware_profile" elements inside "hardware_profiles"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each hardware_profile in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:id].wont_be_nil
     end
+  end
 
-    def test_hardware_profiles_have_name
-      get_auth_url '/api/hardware_profiles'
-      (last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
-        (profile/'name').text.should_not == nil
-      end
+  it 'must include the :href attribute for each "hardware_profile" element in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:href].wont_be_nil
     end
+  end
 
-    def test_hardware_profiles_have_unique_name
-      get_auth_url '/api/hardware_profiles'
-      names = []
-      (last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
-        names << (profile/'name').text
-      end
-      names.should == names.uniq
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:href].must_match /^http/
     end
+  end
 
-    def test_hardware_profiles_have_unique_id
-      get_auth_url '/api/hardware_profiles'
-      ids = []
-      (last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
-        ids << profile['id']
-      end
-      ids.should == ids.uniq
+  it 'must have the URL ending with the :id of the hardware_profile' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:href].must_match /#{r[:id]}$/
     end
+  end
 
-    def test_m1_xlarge_profile_has_correct_attributes
-      get_auth_url '/api/hardware_profiles'
-      profile = (last_xml_response/'hardware_profiles/hardware_profile[@id="m1-xlarge"]')
-      test_profile_properties(profile)
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:hardware_profiles) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each hardware_profile in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      (r/'name').wont_be_empty
     end
+  end
 
-    def test_it_returns_valid_hardware_profile
-      get_auth_url '/api/hardware_profiles/m1-xlarge'
-      profile = (last_xml_response/'hardware_profile')
-      test_profile_properties(profile)
+  it 'should have the "property" element defined if not the opaque hardware_profile' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').wont_be_empty
     end
+  end
 
-    def test_it_responses_to_json
-      get_url '/api/hardware_profiles', {}, { :format => :json }
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['hardware_profiles'].class.should == Array
-      get_url '/api/hardware_profiles/m1-xlarge', {}, { :format => :json }
-      last_response.status.should == 200
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['hardware_profile'].class.should == Hash
+  it 'must define the :kind attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:kind].wont_be_nil }
     end
+  end
 
-    def test_it_responses_to_html
-      get_url '/api/hardware_profiles', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-      get_url '/api/hardware_profiles/m1-xlarge', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
+  it 'must define the :name attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:name].wont_be_nil }
     end
+  end
 
-    def test_it_returns_error_on_wrong_name
-      get_url '/api/hardware_profiles/m1-unknown-wrongname', {}, { :format => :html }
-      last_response.status.should == 404
-      get_auth_url '/api/hardware_profiles/m1-unknown-wrongname'
-      last_response.status.should == 404
-      get_url '/api/hardware_profiles/m1-unknown-wrongname', {}, { :format => :json }
-      last_response.status.should == 404
+  it 'must define the :unit attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:unit].wont_be_nil }
     end
+  end
 
-    private
+  it 'must define the :value attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:value].wont_be_nil }
+    end
+  end
 
-    def test_profile_properties(profile)
-      (profile/'property').each do |properties|
-        properties.attributes.keys.sort.should == [ 'kind', 'name', 'unit', 'value' ]
+  it 'must define the "param" element if property kind is not "fixed"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] == 'fixed'
+        (p/'param').wont_be_empty
+        (p/'param').size.must_equal 1
+        (p/'param').first[:href].wont_be_nil
+        (p/'param').first[:href].must_match /^http/
+        (p/'param').first[:method].wont_be_nil
+        (p/'param').first[:name].wont_be_nil
+        (p/'param').first[:operation].wont_be_nil
       end
+    end
+  end
 
-      (profile/'property[@name="architecture"]').first['kind'].should == 'fixed'
-      (profile/'property[@name="architecture"]').first['unit'].should == 'label'
+  it 'must provide the list of valid values when the property is defined as "enum"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'enum'
+        (p/'enum/entry').wont_be_empty
+        (p/'enum/entry').each { |e| e[:value].wont_be_nil }
+      end
+    end
+  end
 
-      (profile/'property[@name="memory"]').first['kind'].should == 'range'
-      (profile/'property[@name="memory"]').first['unit'].should == 'MB'
-      (profile/'property[@name="memory"]/range').length.should == 1
-      (profile/'property[@name="memory"]/range').first.attributes.keys.sort.should == [ 'first', 'last' ]
+  it 'must provide the range of valid values when the property is defined as "range"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'range'
+        (p/'range').wont_be_empty
+        (p/'range').size.must_equal 1
+        (p/'range').first[:first].wont_be_nil
+        (p/'range').first[:last].wont_be_nil
+      end
+    end
+  end
 
-      (profile/'property[@name="cpu"]').first['kind'].should == 'fixed'
-      (profile/'property[@name="cpu"]').first['unit'].should == 'count'
+  it 'must provide the default value within the range if property defined as "range"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'range'
+        ((p/'range').first[:first].to_i..(p/'range').first[:last].to_i).include?(p[:value].to_i).must_equal true
+      end
+    end
+  end
 
-      (profile/'property[@name="storage"]').first['kind'].should == 'enum'
-      (profile/'property[@name="storage"]').first['unit'].should == 'GB'
-      (profile/'property[@name="storage"]/enum').length.should == 1
-      (profile/'property[@name="storage"]/enum/entry').length.should == 3
-      (profile/'property[@name="storage"]/enum/entry').each do |entry|
-        entry.attributes.keys.should == [ 'value' ]
-        entry['value'].should_not == nil
+  it 'must provide the default value that is included in enum list if property defined as "enum"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'enum'
+        (p/'enum/entry').map { |e| e[:value] }.include?(p[:value]).must_equal true
       end
     end
+  end
 
+  it 'must return the full "hardware_profile" when following the URL in hardware_profile element' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      get collection_url(:hardware_profiles) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
   end
+
+  it 'must have the "name" element for the hardware_profile and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      get collection_url(:hardware_profiles) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
 end
diff --git a/server/tests/drivers/mock/images_test.rb b/server/tests/drivers/mock/images_test.rb
index 47fb690..3faf752 100644
--- a/server/tests/drivers/mock/images_test.rb
+++ b/server/tests/drivers/mock/images_test.rb
@@ -1,138 +1,194 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class HardwareProfilesTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
+describe 'Deltacloud API Images' do
+  include Deltacloud::Test
 
-    def test_it_require_authentication
-      require_authentication?('/api/images').should == true
-    end
+  it 'must advertise have the images collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=images]').wont_be_empty
+  end
 
-    def test_it_returns_images
-      get_auth_url '/api/images', {}
-      (last_xml_response/'images/image').length.should > 0
-    end
+  it 'must require authentication to access the "image" collection' do
+    get collection_url(:images)
+    last_response.status.must_equal 401
+  end
 
-    def test_it_has_correct_attributes_set
-      get_auth_url '/api/images', {}
-      (last_xml_response/'images/image').each do |image|
-        image.attributes.keys.sort.should == [ 'href', 'id' ]
-      end
+  it 'should respond with HTTP_OK when accessing the :images collection with authentication' do
+    auth_as_mock
+    get collection_url(:images)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:images)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:images)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "images" element on top level' do
+    auth_as_mock
+    get collection_url(:images)
+    xml_response.root.name.must_equal 'images'
+  end
+
+  it 'must have some "image" elements inside "images"' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each image in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:id].wont_be_nil
     end
+  end
 
-    def test_img1_has_correct_attributes
-      get_auth_url '/api/images', {}
-      image = (last_xml_response/'images/image[@id="img1"]')
-      test_image_attributes(image)
+  it 'must include the :href attribute for each "image" element in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:href].wont_be_nil
     end
+  end
 
-    def test_it_returns_valid_image
-      get_auth_url '/api/images/img1', {}
-      image = (last_xml_response/'image')
-      test_image_attributes(image)
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:href].must_match /^http/
     end
+  end
 
-    def test_it_has_unique_ids
-      get_auth_url '/api/images', {}
-      ids = []
-      (last_xml_response/'images/image').each do |image|
-        ids << image['id'].to_s
-      end
-      ids.sort.should == ids.sort.uniq
+  it 'must have the URL ending with the :id of the image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:href].must_match /#{r[:id]}$/
     end
+  end
 
-    def test_it_has_valid_urls
-      get_auth_url '/api/images', {}
-      ids = []
-      images = (last_xml_response/'images/image')
-      images.each do |image|
-        get_auth_url image['href'].to_s, {}
-        (last_xml_response/'image').first['href'].should == image['href'].to_s
-      end
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:images) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each image in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      (r/'name').wont_be_empty
     end
+  end
 
-    def test_it_can_filter_using_owner_id
-      get_auth_url '/api/images', { :owner_id => 'mockuser' }
-      (last_xml_response/'images/image').length.should == 1
-      (last_xml_response/'images/image/owner_id').first.text.should == 'mockuser'
+  it 'must have the "state" element defined for each image in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      (r/'state').wont_be_empty
     end
+  end
 
-    def test_it_can_filter_using_unknown_owner_id
-      get_auth_url '/api/images', { :architecture => 'unknown_user' }
-      (last_xml_response/'images/image').length.should == 0
+  it 'must return the full "image" when following the URL in image element' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      last_response.status.must_equal 200
     end
+  end
 
-    def test_it_can_filter_using_architecture
-      get_auth_url '/api/images', { :architecture => 'x86_64' }
-      (last_xml_response/'images/image').length.should == 1
-      (last_xml_response/'images/image/architecture').first.text.should == 'x86_64'
+  it 'must have the "name" element for the image and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
     end
+  end
 
-    def test_it_can_filter_using_unknown_architecture
-      get_auth_url '/api/images', { :architecture => 'unknown_arch' }
-      (last_xml_response/'images/image').length.should == 0
+  it 'must have the "name" element for the image and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
     end
+  end
 
-    def test_it_responses_to_json
-      get_auth_url '/api/images', {}, { :format => :json }
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['images'].class.should == Array
-      get_auth_url '/api/images/img1', {}, { :format => :json }
-      last_response.status.should == 200
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['image'].class.should == Hash
+  it 'should have the "owner_id" element for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'owner_id').wont_be_empty
     end
+  end
 
-    def test_it_responses_to_html
-      get_auth_url '/api/images', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-      get_auth_url '/api/images/img1', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
+  it 'should have the "description" element for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'description').wont_be_empty
     end
+  end
 
-    def test_it_creates_and_destroys_image_from_instance
-      post_url "/api/images", { :name => "img4", :description => "Test::Unit image", :instance_id => "inst1"}
-      last_response.status.should == 201
-      last_response.headers['Location'].should_not == nil
-      get_auth_url last_response.headers['Location'], {}
-      (last_xml_response/'instance/name').should_not == nil
-      delete_url "/api/images/img4", {}
-      last_response.status.should == 204
-      get_auth_url "/api/images/img4", {}
-      last_response.status.should == 404
+  it 'should have the "architecture" element for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'architecture').wont_be_empty
     end
+  end
 
-    private
+  it 'should include the list of compatible hardware_profiles for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
+      (xml_response/'hardware_profiles/hardware_profile').each do |hwp|
+        hwp[:href].wont_be_nil
+        hwp[:href].must_match /^http/
+        hwp[:id].wont_be_nil
+        hwp[:href].must_match /\/#{hwp[:id]}$/
+        hwp[:rel].must_equal 'hardware_profile'
+      end
+    end
+  end
 
-    def test_image_attributes(image)
-      (image/'name').text.should_not nil
-      (image/'owner_id').text.should_not nil
-      (image/'description').text.should_not nil
-      (image/'architecture').text.should_not nil
+  it 'should advertise the list of actions that can be executed for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'actions/link').wont_be_empty
+      (xml_response/'actions/link').each do |l|
+        l[:href].wont_be_nil
+        l[:href].must_match /^http/
+        l[:method].wont_be_nil
+        l[:rel].wont_be_nil
+      end
     end
+  end
 
+  it 'should give client HTML form to create new image' do
+    auth_as_mock
+    header 'Accept', 'text/html'
+    get collection_url(:images) + '/new'
+    last_response.status.must_equal 200
   end
+
 end
diff --git a/server/tests/drivers/mock/instance_states_test.rb b/server/tests/drivers/mock/instance_states_test.rb
deleted file mode 100644
index 905cff3..0000000
--- a/server/tests/drivers/mock/instance_states_test.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class RealmsTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
-
-    def test_it_returns_instance_states
-      get_auth_url '/api/instance_states', {}
-      (last_xml_response/'states/state').length.should > 0
-    end
-
-    def test_each_state_has_transition
-      get_auth_url '/api/instance_states', {}
-      (last_xml_response/'states/state').each do |state|
-        next if state['name'].eql?('finish') # Finnish state doesn't have transitions
-        (state/'transition').length.should > 0
-        (state/'transition').each do |transition|
-          transition['to'].should_not == nil
-        end
-      end
-    end
-
-    def test_it_responses_to_json
-      # FIXME: This test is suffering from conflict between JSON gem and Activesupport
-      # gem in EC2.
-      #
-      #do_request '/api/instance_states', {}, false, { :format => :json }
-      #JSON::parse(last_response.body).class.should == Array
-      #JSON::parse(last_response.body).first['transitions'].class.should == Array
-      #JSON::parse(last_response.body).first['name'].should == 'start'
-    end
-
-    def test_it_responses_to_html
-      get_url '/api/instance_states', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-    end
-
-    def test_it_responses_to_png
-      get_url '/api/instance_states', { :format => 'png' }
-      last_response.status.should == 200
-      last_response.headers['Content-Type'].should =~ /^image\/png/
-    end
-
-  end
-end
diff --git a/server/tests/drivers/mock/instances_test.rb b/server/tests/drivers/mock/instances_test.rb
index 45bb4b8..c601a6f 100644
--- a/server/tests/drivers/mock/instances_test.rb
+++ b/server/tests/drivers/mock/instances_test.rb
@@ -1,253 +1,340 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class InstancesTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
-
-    def test_it_require_authentication
-      require_authentication?('/api/instances').should == true
-    end
-
-    def test_it_returns_instances
-      get_auth_url '/api/instances', {}
-      (last_xml_response/'instances/instance').length.should > 0
-    end
-
-    def test_it_has_correct_attributes_set
-      get_auth_url '/api/images', {}
-      (last_xml_response/'images/image').each do |image|
-        image.attributes.keys.sort.should == [ 'href', 'id' ]
-      end
+describe 'Deltacloud API instances' do
+  include Deltacloud::Test
+
+  it 'must advertise have the instances collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=instances]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "instance" collection' do
+    get collection_url(:instances)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :instances collection with authentication' do
+    auth_as_mock
+    get collection_url(:instances)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:instances)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:instances)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "instances" element on top level' do
+    auth_as_mock
+    get collection_url(:instances)
+    xml_response.root.name.must_equal 'instances'
+  end
+
+  it 'must have some "instance" elements inside "instances"' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each instance in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:id].wont_be_nil
     end
+  end
 
-    def test_it_has_unique_ids
-      get_auth_url '/api/instances', {}
-      ids = []
-      (last_xml_response/'instances/instance').each do |image|
-        ids << image['id'].to_s
-      end
-      ids.sort.should == ids.sort.uniq
-    end
-
-    def test_inst1_has_correct_attributes
-      get_auth_url '/api/instances', {}
-      instance = (last_xml_response/'instances/instance[@id="inst1"]')
-      test_instance_attributes(instance)
-    end
-
-    def test_it_returns_valid_realm
-      get_auth_url '/api/instances/inst1', {}
-      instance = (last_xml_response/'instance')
-      test_instance_attributes(instance)
-    end
-
-    def test_it_responses_to_json
-      get_auth_url '/api/instances', {}, { :format => :json }
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['instances'].class.should == Array
-
-      get_auth_url '/api/instances/inst1', {}, { :format => :json }
-      last_response.status.should == 200
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['instance'].class.should == Hash
-    end
-
-    def test_it_responses_to_html
-      get_auth_url '/api/instances', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-      get_auth_url '/api/instances/inst1', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-    end
-
-    def test_it_create_a_new_instance_using_image_id
-      params = {
-        :image_id => 'img1'
-      }
-      post_url '/api/instances', params
-      last_response.status.should == 201
-      last_response.headers['Location'].should_not == nil
-      get_auth_url last_response.headers['Location'], {}
-      (last_xml_response/'instance/name').should_not == nil
-      add_created_instance (last_xml_response/'instance').first['id']
-      test_instance_attributes(last_xml_response/'instance')
-    end
-
-    def test_it_create_a_new_instance_using_image_id_and_name
-      params = {
-        :image_id => 'img1',
-        :name => "unit_test_instance1"
-      }
-      post_url '/api/instances', params
-      last_response.status.should == 201
-      last_response.headers['Location'].should_not == nil
-      get_auth_url last_response.headers['Location'], {}
-      (last_xml_response/'instance/name').text.should == 'unit_test_instance1'
-      add_created_instance (last_xml_response/'instance').first['id']
-      test_instance_attributes(last_xml_response/'instance')
-    end
-
-    def test_it_create_a_new_instance_using_image_id_and_name_and_hwp_storage_and_hwp_cpu
-      params = {
-        :image_id => 'img1',
-        :realm_id => '',
-        :name => "unit_test_instance3",
-        :hwp_id => "m1-large",
-        :hwp_storage => '850',
-        :hwp_memory => '7680.0',
-        :hwp_cpu => "1.0",
-      }
-      post_url '/api/instances', params
-      last_response.status.should == 400
-    end
-
-    def test_it_create_a_new_instance_using_image_id_and_name_and_hwp_storage
-      params = {
-        :image_id => 'img1',
-        :name => "unit_test_instance2",
-        :hwp_id => "m1-small",
-        :hwp_storage => "160"
-      }
-      post_url '/api/instances', params
-      last_response.status.should == 201
-      last_response.headers['Location'].should_not == nil
-      get_auth_url last_response.headers['Location'], {}
-      (last_xml_response/'instance/name').text.should == 'unit_test_instance2'
-      (last_xml_response/'instance/hardware_profile').first['id'].should == 'm1-small'
-      add_created_instance (last_xml_response/'instance').first['id']
-      test_instance_attributes(last_xml_response/'instance')
-    end
-
-    def test_it_z0_stop_and_start_instance
-      $created_instances.each do |instance_id|
-        get_auth_url "/api/instances/#{instance_id}", {}
-        stop_url = (last_xml_response/'actions/link[@rel="stop"]').first['href']
-        stop_url.should_not == nil
-        post_url stop_url
-        last_response.status.should == 200
-        instance = Nokogiri::XML(last_response.body)
-        test_instance_attributes(instance)
-        (instance/'state').text.should == 'STOPPED'
-        get_auth_url "/api/instances/#{instance_id}", {}
-        start_url = (last_xml_response/'actions/link[@rel="start"]').first['href']
-        start_url.should_not == nil
-        post_url start_url
-        last_response.status.should == 200
-        instance = Nokogiri::XML(last_response.body)
-        test_instance_attributes(instance)
-        (instance/'state').text.should == 'RUNNING'
-      end
+  it 'must include the :href attribute for each "instance" element in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:href].wont_be_nil
     end
+  end
 
-    def test_z0_reboot_instance
-      $created_instances.each do |instance_id|
-        get_auth_url "/api/instances/#{instance_id}", {}
-        reboot_url = (last_xml_response/'actions/link[@rel="reboot"]').first['href']
-        reboot_url.should_not == nil
-        post_url reboot_url
-        last_response.status.should == 202
-        instance = Nokogiri::XML(last_response.body)
-        test_instance_attributes(instance)
-        (instance/'state').text.should == 'RUNNING'
-      end
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:href].must_match /^http/
     end
+  end
 
-    def test_z1_stop_created_instances
-      $created_instances.each do |instance_id|
-        get_auth_url "/api/instances/#{instance_id}", {}
-        stop_url = (last_xml_response/'actions/link[@rel="stop"]').first['href']
-        stop_url.should_not == nil
-        post_url stop_url, {}
-        last_response.status.should == 200
-        instance = Nokogiri::XML(last_response.body)
-        test_instance_attributes(instance)
-        (instance/'state').text.should == 'STOPPED'
-      end
+  it 'must have the URL ending with the :id of the instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:href].must_match /#{r[:id]}$/
     end
+  end
 
-    def test_z2_destroy_created_instances
-      $created_instances.each do |instance_id|
-        get_auth_url "/api/instances/#{instance_id}", {}
-        destroy_url = (last_xml_response/'actions/link[@rel="destroy"]').first['href']
-        destroy_url.should_not == nil
-        delete_url destroy_url, {}
-        last_response.status.should == 204
-      end
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:instances) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each instance in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      (r/'name').wont_be_empty
     end
+  end
 
-    def test_create_key_returns_201
-      post_url '/api/keys', {:name => Time.now.to_f.to_s}
-      last_response.status.should == 201
+  it 'must have the "state" element defined for each instance in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      (r/'state').wont_be_empty
+      (r/'state').first.must_match /(RUNNING|STOPPED|PENDING)/
     end
+  end
 
-    private
+  it 'must return the full "instance" when following the URL in instance element' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
 
-    def test_instance_attributes(instance)
-      (instance/'name').should_not == nil
-      (instance/'owner_id').should_not == nil
-      ['RUNNING', 'STOPPED'].include?((instance/'state').text).should == true
+  it 'must have the "name" element for the instance and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "name" element for the instance and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
+  end
+
+  it 'must have the "owner_id" element for the instance and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'owner_id').wont_be_empty
+      (xml_response/'owner_id').first.text.must_equal((r/'owner_id').first.text)
+    end
+  end
+
+  it 'must link to the realm that was used to during instance creation' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'realm').wont_be_empty
+      (xml_response/'realm').size.must_equal 1
+      (xml_response/'realm').first[:id].wont_be_nil
+      (xml_response/'realm').first[:href].wont_be_nil
+      (xml_response/'realm').first[:href].must_match /\/#{(xml_response/'realm').first[:id]}$/
+    end
+  end
 
-      (instance/'public_addreses').should_not == nil
-      (instance/'public_addresses/address').to_a.size.should > 0
-      (instance/'public_addresses/address').first.text.should_not == ""
-      (instance/'public_addresses/address').first[:type].should == "hostname"
+  it 'must link to the image that was used to during instance creation' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'image').wont_be_empty
+      (xml_response/'image').size.must_equal 1
+      (xml_response/'image').first[:id].wont_be_nil
+      (xml_response/'image').first[:href].wont_be_nil
+      (xml_response/'image').first[:href].must_match /\/#{(xml_response/'image').first[:id]}$/
+    end
+  end
 
-      (instance/'private_addresses').should_not == nil
-      (instance/'private_addresses/address').to_a.size.should > 0
-      (instance/'private_addresses/address').first.text.should_not == ""
-      (instance/'private_addresses/address').first[:type].should == "hostname"
+  it 'must link to the hardware_profile that was used to during instance creation' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'hardware_profile').wont_be_empty
+      (xml_response/'hardware_profile').size.must_equal 1
+      (xml_response/'hardware_profile').first[:id].wont_be_nil
+      (xml_response/'hardware_profile').first[:href].wont_be_nil
+      (xml_response/'hardware_profile').first[:href].must_match /\/#{(xml_response/'hardware_profile').first[:id]}$/
+    end
+  end
 
-      (instance/'actions/link').to_a.size.should > 0
-      (instance/'actions/link').each do |link|
-        link['href'].should_not == ""
-        link['rel'].should_not == ""
-        link['method'].should_not == ""
-        ['get', 'post', 'delete', 'put'].include?(link['method']).should == true
+  it 'should advertise the public and private addresses of the instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'public_addresses').wont_be_empty
+      (xml_response/'public_addresses').size.must_equal 1
+      (xml_response/'public_addresses/address').each do |a|
+        a[:type].wont_be_nil
+        a.text.strip.wont_be_empty
       end
+      (xml_response/'private_addresses').wont_be_empty
+      (xml_response/'private_addresses').size.must_equal 1
+      (xml_response/'private_addresses/address').each do |a|
+        a[:type].wont_be_nil
+        a.text.strip.wont_be_empty
+      end
+    end
+  end
 
-      (instance/'image').size.should > 0
-      (instance/'image').first['href'].should_not == ""
-      (instance/'image').first['id'].should_not == ""
-      get_auth_url (instance/'image').first['href'], {}
-      (last_xml_response/'image').should_not == nil
-      (last_xml_response/'image').first['href'] == (instance/'image').first['href']
+  it 'should advertise the storage volumes used by the instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'storage_volumes').wont_be_empty
+    end
+  end
 
-      (instance/'realm').size.should > 0
-      (instance/'realm').first['href'].should_not == ""
-      (instance/'realm').first['id'].should_not == ""
-      get_auth_url (instance/'realm').first['href']
-      (last_xml_response/'realm').should_not == nil
-      (last_xml_response/'realm').first['href'] == (instance/'realm').first['href']
+  it 'should advertise the list of actions that can be executed for each instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'actions/link').wont_be_empty
+      (xml_response/'actions/link').each do |l|
+        l[:href].wont_be_nil
+        l[:href].must_match /^http/
+        l[:method].wont_be_nil
+        l[:rel].wont_be_nil
+      end
+    end
+  end
 
-      (instance/'hardware_profile').size.should > 0
-      (instance/'hardware_profile').first['href'].should_not == ""
-      (instance/'hardware_profile').first['id'].should_not == ""
-      get_auth_url (instance/'hardware_profile').first['href']
-      (last_xml_response/'hardware_profile').should_not == nil
-      (last_xml_response/'hardware_profile').first['href'] == (instance/'hardware_profile').first['href']
+  it 'should allow to create and destroy new instance using the first available image without realm' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    image_id.wont_be_nil
+    post collection_url(:instances), {
+      :image_id => image_id
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
     end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
 
+  it 'should allow to create and destroy new instance using the first available image within first realm' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    get collection_url(:realms)
+    realm_id = (xml_response/'realms/realm').first[:id]
+    image_id.wont_be_nil
+    realm_id.wont_be_nil
+    post collection_url(:instances), {
+      :image_id => image_id,
+      :realm_id => realm_id,
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    (xml_response/'instance/realm').first[:id].must_equal realm_id
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
   end
+
+  it 'should allow to create and destroy new instance using the first available image with user defined name' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    image_id.wont_be_nil
+    name = "i#{Time.now.to_i}"
+    post collection_url(:instances), {
+      :image_id => image_id,
+      :name => name
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    (xml_response/'instance/name').first.text.must_equal name
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+  it 'should allow to create and destroy new instance using the first available image and first hardware_profile' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    get collection_url(:hardware_profiles)
+    hwp_id = (xml_response/'hardware_profiles/hardware_profile').first[:id]
+    image_id.wont_be_nil
+    name = "i#{Time.now.to_i}"
+    post collection_url(:instances), {
+      :image_id => image_id,
+      :hwp_id => hwp_id
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    (xml_response/'instance/hardware_profile').first[:id].must_equal hwp_id
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
 end
diff --git a/server/tests/drivers/mock/keys_test.rb b/server/tests/drivers/mock/keys_test.rb
new file mode 100644
index 0000000..9267b5a
--- /dev/null
+++ b/server/tests/drivers/mock/keys_test.rb
@@ -0,0 +1,158 @@
+describe 'Deltacloud API Keys' do
+  include Deltacloud::Test
+
+  it 'must advertise have the keys collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=keys]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "key" collection' do
+    get collection_url(:keys)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :keys collection with authentication' do
+    auth_as_mock
+    get collection_url(:keys)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:keys)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:keys)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "keys" element on top level' do
+    auth_as_mock
+    get collection_url(:keys)
+    xml_response.root.name.must_equal 'keys'
+  end
+
+  it 'must have some "key" elements inside "keys"' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').wont_be_empty
+  end
+
+  it 'must tell the kind of "key" elements inside "keys"' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |k|
+      k[:type].must_match /(key|password)/
+    end
+  end
+
+  it 'must provide the :id attribute for each key in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "key" element in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the key' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:keys) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each key in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+
+  it 'must return the full "key" when following the URL in key element' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the key and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "name" element for the key and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
+  end
+
+  it 'should advertise the list of actions that can be executed for each key' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      (xml_response/'actions/link').wont_be_empty
+      (xml_response/'actions/link').each do |l|
+        l[:href].wont_be_nil
+        l[:href].must_match /^http/
+        l[:method].wont_be_nil
+        l[:rel].wont_be_nil
+      end
+    end
+  end
+
+  it 'should allow to create a new key and then remove it' do
+    auth_as_mock
+    key_name = Time.now.to_i.to_s
+    post collection_url(:keys), {
+      :name => 'test_key_'+key_name
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    get collection_url(:keys) + '/' + 'test_key_'+key_name
+    last_response.status.must_equal 200 # HTTP_OK
+    delete collection_url(:keys) + '/' + 'test_key_'+key_name
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+end
diff --git a/server/tests/drivers/mock/realms_test.rb b/server/tests/drivers/mock/realms_test.rb
index b0db9e4..6bc9101 100644
--- a/server/tests/drivers/mock/realms_test.rb
+++ b/server/tests/drivers/mock/realms_test.rb
@@ -1,89 +1,129 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class RealmsTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
+describe 'Deltacloud API Realms' do
+  include Deltacloud::Test
 
-    def test_it_returns_realms
-      get_auth_url '/api/realms', {}
-      (last_xml_response/'realms/realm').length.should > 0
-    end
+  it 'must advertise have the realms collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=realms]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "realm" collection' do
+    get collection_url(:realms)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :realms collection with authentication' do
+    auth_as_mock
+    get collection_url(:realms)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:realms)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:realms)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "realms" element on top level' do
+    auth_as_mock
+    get collection_url(:realms)
+    xml_response.root.name.must_equal 'realms'
+  end
+
+  it 'must have some "realm" elements inside "realms"' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').wont_be_empty
+  end
 
-    def test_it_has_correct_attributes_set
-      get_auth_url '/api/realms', {}
-      (last_xml_response/'realms/realm').each do |realm|
-        realm.attributes.keys.sort.should == [ 'href', 'id' ]
-      end
+  it 'must provide the :id attribute for each realm in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:id].wont_be_nil
     end
+  end
 
-    def test_us_has_correct_attributes
-      get_auth_url '/api/realms', {}
-      realm = (last_xml_response/'realms/realm[@id="us"]')
-      test_realm_attributes(realm)
+  it 'must include the :href attribute for each "realm" element in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:href].wont_be_nil
     end
+  end
 
-    def test_it_returns_valid_realm
-      get_auth_url '/api/realms/us', {}
-      realm = (last_xml_response/'realm')
-      test_realm_attributes(realm)
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:href].must_match /^http/
     end
+  end
 
-    def test_it_has_unique_ids
-      get_auth_url '/api/realms', {}
-      ids = []
-      (last_xml_response/'realms/realm').each do |realm|
-        ids << realm['id'].to_s
-      end
-      ids.sort.should == ids.sort.uniq
+  it 'must have the URL ending with the :id of the realm' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:href].must_match /#{r[:id]}$/
     end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:realms) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
 
-    def test_it_responses_to_json
-      get_auth_url '/api/realms', {}, { :format => :json }
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['realms'].class.should == Array
-      get_auth_url '/api/realms/us', {}, { :format => :json }
-      last_response.status.should == 200
-      JSON::parse(last_response.body).class.should == Hash
-      JSON::parse(last_response.body)['realm'].class.should == Hash
+  it 'must have the "name" element defined for each realm in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      (r/'name').wont_be_empty
     end
+  end
 
-    def test_it_responses_to_html
-      get_auth_url '/api/realms', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
-      get_auth_url '/api/realms/us', {}, { :format => :html }
-      last_response.status.should == 200
-      Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
+  it 'must have the "state" element defined for each realm in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      (r/'state').wont_be_empty
     end
+  end
 
-    private
+  it 'must return the full "realm" when following the URL in realm element' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      get collection_url(:realms) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
 
-    def test_realm_attributes(realm)
-      (realm/'name').should_not == nil
-      (realm/'limit').should_not == nil
-      ['AVAILABLE'].include?((realm/'state').text).should == true
+  it 'must have the "name" element for the realm and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      get collection_url(:realms) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
     end
+  end
 
+  it 'must have the "state" element for the realm and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      get collection_url(:realms) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
   end
+
 end
diff --git a/server/tests/drivers/mock/setup.rb b/server/tests/drivers/mock/setup.rb
deleted file mode 100644
index 60a7094..0000000
--- a/server/tests/drivers/mock/setup.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-ENV['API_DRIVER']   = "mock"
-ENV['API_USER']     = 'mockuser'
-ENV['API_PASSWORD'] = 'mockpassword'
diff --git a/server/tests/drivers/mock/storage_snapshots_test.rb b/server/tests/drivers/mock/storage_snapshots_test.rb
new file mode 100644
index 0000000..52ea847
--- /dev/null
+++ b/server/tests/drivers/mock/storage_snapshots_test.rb
@@ -0,0 +1,111 @@
+describe 'Deltacloud API storage_snapshots' do
+  include Deltacloud::Test
+
+  it 'must advertise have the storage_snapshots collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=storage_snapshots]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "storage_snapshot" collection' do
+    get collection_url(:storage_snapshots)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :storage_snapshots collection with authentication' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:storage_snapshots)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "storage_snapshots" element on top level' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    xml_response.root.name.must_equal 'storage_snapshots'
+  end
+
+  it 'must have some "storage_snapshot" elements inside "storage_snapshots"' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each storage_snapshot in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "storage_snapshot" element in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the storage_snapshot' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:storage_snapshots) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each storage_snapshot in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must return the full "storage_snapshot" when following the URL in storage_snapshot element' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      get collection_url(:storage_snapshots) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the storage_snapshot and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      get collection_url(:storage_snapshots) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+end
diff --git a/server/tests/drivers/mock/storage_volumes_test.rb b/server/tests/drivers/mock/storage_volumes_test.rb
new file mode 100644
index 0000000..cbafd5d
--- /dev/null
+++ b/server/tests/drivers/mock/storage_volumes_test.rb
@@ -0,0 +1,119 @@
+describe 'Deltacloud API storage_volumes' do
+  include Deltacloud::Test
+
+  it 'must advertise have the storage_volumes collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=storage_volumes]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "storage_volume" collection' do
+    get collection_url(:storage_volumes)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :storage_volumes collection with authentication' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:storage_volumes)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "storage_volumes" element on top level' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    xml_response.root.name.must_equal 'storage_volumes'
+  end
+
+  it 'must have some "storage_volume" elements inside "storage_volumes"' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each storage_volume in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "storage_volume" element in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the storage_volume' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:storage_volumes) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each storage_volume in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must have the "state" element defined for each storage_volume in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      (r/'state').wont_be_empty
+    end
+  end
+
+  it 'must return the full "storage_volume" when following the URL in storage_volume element' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      get collection_url(:storage_volumes) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the storage_volume and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      get collection_url(:storage_volumes) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+end
diff --git a/server/tests/drivers/mock/url_for_test.rb b/server/tests/drivers/mock/url_for_test.rb
deleted file mode 100644
index ccd4ebf..0000000
--- a/server/tests/drivers/mock/url_for_test.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-module DeltacloudUnitTest
-  class UrlForTest < Test::Unit::TestCase
-    include Rack::Test::Methods
-
-    def app
-      Sinatra::Application
-    end
-
-    def test_it_works_for_root
-      verify_url_for("/", "/")
-    end
-
-    def test_it_works_for_root_absolute
-      verify_url_for("/", "http://example.org/", :full)
-    end
-
-    def test_it_works_with_spaces
-      verify_url_for("/url with spaces", "/url%20with%20spaces")
-    end
-
-    def test_it_works_when_given_absolute
-      verify_url_for("http://test.com", "http://test.com")
-    end
-
-    def test_it_works_when_not_at_root_context
-      verify_url_for("/", "context/", :path_only, {}, {"SCRIPT_NAME" => "context"})
-    end
-
-    def verify_url_for(url, expected_url, mode=:path_only, params={}, rack_env={})
-      # generate a unique url for each test
-      test_url = "/url_for_test/#{expected_url.hash}/#{Time.now.to_i}"
-      # Create our sinatra test endpoint
-      self.class.create_test_url_content(test_url, url, mode)
-
-      # verify the generated url matches what we expect
-      get test_url, params, rack_env
-      last_response.body.should == expected_url
-    end
-
-    def self.create_test_url_content(test_url, url_content, mode)
-      get test_url do
-        content_type "text/plain"
-          url_for(url_content, mode)
-      end
-    end
-
-  end
-end
-- 
1.7.10.1


Re: [PATCH core 33/51] EC2: Fixed cucumber tests for Amazon EC2

Posted by David Lutterkort <lu...@redhat.com>.
On Mon, 2012-05-21 at 12:07 +0200, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>

Leftover debugging statement:
 
> diff --git a/tests/ec2/step_definitions/storage_volumes_steps.rb b/tests/ec2/step_definitions/storage_volumes_steps.rb
> index afd2f37..a6cd0a4 100644
> --- a/tests/ec2/step_definitions/storage_volumes_steps.rb
> +++ b/tests/ec2/step_definitions/storage_volumes_steps.rb
> @@ -72,6 +72,7 @@ end
>  
>  Then /^storage_volume should be attached to this instance$/ do
>    get "/api/storage_volumes/vol-de30ccb4"
> +  puts last_response.body
>    (output_xml/"/storage_volume/mount/instance").first['id'].should == 'i-7f6a021e'
>  end

> diff --git a/tests/ec2/support/env.rb b/tests/ec2/support/env.rb
> index 5eb006a..39dd5ee 100644
> --- a/tests/ec2/support/env.rb
> +++ b/tests/ec2/support/env.rb
> @@ -1,26 +1,29 @@
>  require 'rubygems'
>  require 'nokogiri'
> -
> -SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
> -$top_srcdir = SERVER_DIR
> -$:.unshift File::join($top_srcdir, 'lib')
> -Dir.chdir(SERVER_DIR)
> -
> -API_VERSION = "9.9.9"
> -API_ROOT_URL = "/api"
> +require 'rack/test'
>  
>  ENV['API_DRIVER'] = 'ec2'
> -ENV.delete('API_VERBOSE')
> -
> -load File.join($top_srcdir, 'lib', 'deltacloud', 'server.rb')
>  
> -require 'rack/test'
> +#CONFIG = {
> +#  :username => 'AKIAI77KNAA7ZXRLL7GQ',
> +#  :password => 'idJ9vktNaDWAK0LWVVE/526ONvJmTl2Crto/s8Ok'
> +#}

Might wanna revoke that key ;) We should use ~/.deltacloud/config or
similar for credentials for running tests.

David



[PATCH core 33/51] EC2: Fixed cucumber tests for Amazon EC2

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/views/storage_volumes/show.xml.haml         |    2 +-
 tests/ec2/images.feature                           |    2 +
 tests/ec2/step_definitions/instances_steps.rb      |    2 +-
 .../ec2/step_definitions/storage_volumes_steps.rb  |    1 +
 tests/ec2/support/ec2_mock_driver.rb               |   72 +++++++++++++++++
 tests/ec2/support/env.rb                           |   27 ++++---
 tests/ec2/support/method_serializer.rb             |   83 ++++++++++++++++++++
 7 files changed, 175 insertions(+), 14 deletions(-)
 create mode 100644 tests/ec2/support/ec2_mock_driver.rb
 create mode 100644 tests/ec2/support/method_serializer.rb

diff --git a/server/views/storage_volumes/show.xml.haml b/server/views/storage_volumes/show.xml.haml
index f9f5f25..ccd1baa 100644
--- a/server/views/storage_volumes/show.xml.haml
+++ b/server/views/storage_volumes/show.xml.haml
@@ -30,4 +30,4 @@
   - if @storage_volume.actions
     %actions
       - @storage_volume.actions.each do |action|
-        %link{:rel => action, :method => action_method(action, :storage_volumes), :href => self.send("#{action}_storage_volume_url", @storage_volume.id)}
+        %link{:rel => action, :method => :post, :href => self.send("#{action}_storage_volume_url", @storage_volume.id)}
diff --git a/tests/ec2/images.feature b/tests/ec2/images.feature
index 9fdd721..139b385 100644
--- a/tests/ec2/images.feature
+++ b/tests/ec2/images.feature
@@ -13,6 +13,7 @@ Feature: Listing and showing images
     | owner_id |
     | state |
     | actions |
+    | hardware_profiles |
     And each image should have 'href' attribute with valid URL
     And this URI should be available in XML, JSON, HTML format
 
@@ -32,6 +33,7 @@ Feature: Listing and showing images
     | owner_id |
     | state |
     | actions |
+    | hardware_profiles |
     And this URI should be available in XML, JSON, HTML format
 
   Scenario: Filtering images by owner_id
diff --git a/tests/ec2/step_definitions/instances_steps.rb b/tests/ec2/step_definitions/instances_steps.rb
index 5489394..b8dd871 100644
--- a/tests/ec2/step_definitions/instances_steps.rb
+++ b/tests/ec2/step_definitions/instances_steps.rb
@@ -116,7 +116,7 @@ When /^client want to '(\w+)' created instance$/ do |action|
 end
 
 Then /^client should get created instance$/ do
-  last_response.status.should == 200
+  last_response.status.should == 202
   #get last_response.headers['Location']
 end
 
diff --git a/tests/ec2/step_definitions/storage_volumes_steps.rb b/tests/ec2/step_definitions/storage_volumes_steps.rb
index afd2f37..a6cd0a4 100644
--- a/tests/ec2/step_definitions/storage_volumes_steps.rb
+++ b/tests/ec2/step_definitions/storage_volumes_steps.rb
@@ -72,6 +72,7 @@ end
 
 Then /^storage_volume should be attached to this instance$/ do
   get "/api/storage_volumes/vol-de30ccb4"
+  puts last_response.body
   (output_xml/"/storage_volume/mount/instance").first['id'].should == 'i-7f6a021e'
 end
 
diff --git a/tests/ec2/support/ec2_mock_driver.rb b/tests/ec2/support/ec2_mock_driver.rb
new file mode 100644
index 0000000..c4a6778
--- /dev/null
+++ b/tests/ec2/support/ec2_mock_driver.rb
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require_relative './method_serializer'
+
+# Create 'mock' version of original driver client/gem:
+
+module Mock
+
+  class Ec2 < Aws::Ec2
+
+    include MethodSerializer::Cache
+
+    def self.cached_methods
+      [
+        :describe_images,
+        :describe_images_by_owner,
+        :describe_availability_zones,
+        :launch_instances,
+        :describe_instances,
+        :reboot_instances,
+        :create_tag,
+        :delete_tag,
+        :describe_tags,
+        :terminate_instances,
+        :describe_key_pairs,
+        :create_key_pair,
+        :delete_key_pair,
+        :create_volume,
+        :get_console_output,
+        :describe_volumes,
+        :delete_volume,
+        :attach_volume,
+        :detach_volume,
+        :describe_snapshots,
+        :associate_address,
+        :try_create_snapshot,
+      ]
+    end
+
+    MethodSerializer::Cache::wrap_methods(self, :cache_dir => File.join(File.dirname(__FILE__)))
+  end
+
+end
+
+Deltacloud::Drivers::Ec2::Ec2Driver.class_eval do
+  alias_method :original_new_client, :new_client
+
+  def new_client(credentials, provider = :ec2)
+    auth_credentials = { :access_key_id => credentials.user, :secret_access_key => credentials.password}
+    if provider == :elb
+      Mock::ELB.new(auth_credentials)
+    elsif provider == :s3
+      Mock::S3.new(auth_credentials)
+    else
+      Mock::Ec2.new(auth_credentials[:access_key_id], auth_credentials[:secret_access_key])
+    end
+  end
+
+end
diff --git a/tests/ec2/support/env.rb b/tests/ec2/support/env.rb
index 5eb006a..39dd5ee 100644
--- a/tests/ec2/support/env.rb
+++ b/tests/ec2/support/env.rb
@@ -1,26 +1,29 @@
 require 'rubygems'
 require 'nokogiri'
-
-SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
-$top_srcdir = SERVER_DIR
-$:.unshift File::join($top_srcdir, 'lib')
-Dir.chdir(SERVER_DIR)
-
-API_VERSION = "9.9.9"
-API_ROOT_URL = "/api"
+require 'rack/test'
 
 ENV['API_DRIVER'] = 'ec2'
-ENV.delete('API_VERBOSE')
-
-load File.join($top_srcdir, 'lib', 'deltacloud', 'server.rb')
 
-require 'rack/test'
+#CONFIG = {
+#  :username => 'AKIAI77KNAA7ZXRLL7GQ',
+#  :password => 'idJ9vktNaDWAK0LWVVE/526ONvJmTl2Crto/s8Ok'
+#}
 
 CONFIG = {
   :username => 'mockuser',
   :password => 'mockpassword'
 }
 
+load File.join(File.dirname(__FILE__), '..', '..', '..', 'server', 'lib', 'deltacloud_rack.rb')
+
+Deltacloud::configure do |server|
+  server.root_url '/api'
+  server.version '0.5.0'
+  server.klass 'Deltacloud::API'
+end.require_frontend!
+
+require_relative './ec2_mock_driver'
+
 World do
   include Rack::Test::Methods
 
diff --git a/tests/ec2/support/method_serializer.rb b/tests/ec2/support/method_serializer.rb
new file mode 100644
index 0000000..ff5e542
--- /dev/null
+++ b/tests/ec2/support/method_serializer.rb
@@ -0,0 +1,83 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require 'base64'
+require 'digest'
+
+module MethodSerializer
+
+  module Cache
+
+    def cache_dir
+      storage_dir = $methods_cache_dir || File.join(File.dirname(__FILE__), 'cache')
+      class_dir = self.class.name.split('::').last
+      class_dir ||= self.class.name
+      File.join(storage_dir, class_dir.downcase)
+    end
+
+    def serialize_data(method_name, args, data)
+      File.open(cache_file_name(method_name, args), 'w') do |f|
+        f.puts(Base64.encode64(Marshal.dump(data)))
+      end
+      return data
+    end
+
+    def deserialize_data(method_name, args)
+      begin
+        data = File.readlines(cache_file_name(method_name, args)).join
+        Marshal.load(Base64.decode64(data))
+      rescue Errno::ENOENT
+        return false
+      end
+    end
+
+    def args_hash(args)
+      if args.class == Hash
+        args = args.to_a.collect {|i| [i[0].to_s, i[1]]}.sort
+      end
+      Digest::SHA1.hexdigest(args.to_s)
+    end
+
+    def cache_file_name(method_name, args)
+      FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
+      method_name = $scenario_prefix ? "#{$scenario_prefix}_#{method_name}" : method_name
+      File.join(cache_dir, "#{method_name}.#{args_hash(args)}")
+    end
+
+    def self.wrap_methods(c, opts={})
+      $methods_cache_dir = opts[:cache_dir]
+      $scenario_prefix = nil
+      c.class_eval do
+        cached_methods.each do |m|
+          next if c.instance_methods(false).include?("original_#{m}")
+          alias_method "original_#{m}".to_sym, m.to_sym
+          define_method m.to_sym do |*args|
+            args = args.first if args.size.eql?(1) and not args.first.class.eql?(Array)
+            output = deserialize_data(m, args)
+            unless output
+              output = method("original_#{m}".to_sym).to_proc[args]
+              return serialize_data(m, args, output)
+            else
+              return output
+            end
+          end
+        end
+      end
+    end
+
+  end
+
+end
+
-- 
1.7.10.1


[PATCH core 21/51] Core: Fixed couple errors and typos in buckets/blobs code

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/buckets.rb       |   84 +++++++++++---------
 server/lib/deltacloud/drivers/mock/mock_driver.rb  |    6 +-
 server/lib/deltacloud/helpers/deltacloud_helper.rb |    2 +
 server/lib/deltacloud/helpers/url_helper.rb        |    7 +-
 server/lib/deltacloud/models/bucket.rb             |    4 +
 server/views/buckets/new.html.haml                 |    2 +-
 6 files changed, 60 insertions(+), 45 deletions(-)

diff --git a/server/lib/deltacloud/collections/buckets.rb b/server/lib/deltacloud/collections/buckets.rb
index 044bd6a..3a5591d 100644
--- a/server/lib/deltacloud/collections/buckets.rb
+++ b/server/lib/deltacloud/collections/buckets.rb
@@ -18,8 +18,53 @@ module Deltacloud::Collections
     check_capability :for => lambda { |m| driver.respond_to? m }
     check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
 
+    get route_for('/buckets/new') do
+      respond_to do |format|
+        format.html { haml :"buckets/new" }
+      end
+    end
+
+    get route_for('/buckets/:bucket/%s' % NEW_BLOB_FORM_ID) do
+      @bucket_id = params[:bucket]
+      respond_to do |format|
+        format.html {haml :"blobs/new"}
+      end
+    end
+
     collection :buckets do
 
+      standard_show_operation
+      standard_index_operation
+
+      operation :create, :with_capability => :create_bucket do
+        param :name,      :string,    :required
+        control do
+          @bucket = driver.create_bucket(credentials, params[:name], params)
+          status 201
+          response['Location'] = bucket_url(@bucket.id)
+          respond_to do |format|
+            format.xml  { haml :"buckets/show" }
+            format.json { convert_to_json(:bucket, @bucket) }
+            format.html do
+              redirect bucket_url(@bucket.id) if @bucket and @bucket.id
+              redirect buckets_url
+            end
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :delete_bucket do
+        control do
+          driver.delete_bucket(credentials, params[:id], params)
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html {  redirect(buckets_url) }
+          end
+        end
+      end
+
       collection :blobs, :with_id => :blob_id, :no_member => true do
 
         operation :show, :with_capability => :blob do
@@ -115,7 +160,6 @@ module Deltacloud::Collections
             end
           end
         end
-
         action :metadata, :http_method => :head, :with_capability => :blob_metadata do
           control do
             @blob_id = params[:blob]
@@ -168,46 +212,8 @@ module Deltacloud::Collections
             end
           end
         end
-
-      end
-
-      get route_for('/buckets/new') do
-        respond_to do |format|
-          format.html { haml :"buckets/new" }
-        end
       end
 
-      standard_show_operation
-      standard_index_operation
-
-      operation :create, :with_capability => :create_bucket do
-        param :name,      :string,    :required
-        control do
-          @bucket = driver.create_bucket(credentials, params[:name], params)
-          status 201
-          response['Location'] = bucket_url(@bucket.id)
-          respond_to do |format|
-            format.xml  { haml :"buckets/show" }
-            format.json { convert_to_json(:bucket, @bucket) }
-            format.html do
-              redirect bucket_url(@bucket.id) if @bucket and @bucket.id
-              redirect buckets_url
-            end
-          end
-        end
-      end
-
-      operation :destroy, :with_capability => :delete_bucket do
-        control do
-          driver.delete_bucket(credentials, params[:id], params)
-          status 204
-          respond_to do |format|
-            format.xml
-            format.json
-            format.html {  redirect(buckets_url) }
-          end
-        end
-      end
 
     end
 
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb
index cd7534b..ba817c6 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
@@ -367,7 +367,7 @@ module Deltacloud::Drivers::Mock
       check_credentials(credentials)
       bucket = bucket(credentials, {:id => name})
       raise 'BucketNotExist' if bucket.nil?
-      raise "BucketNotEmpty" unless (bucket and bucket.size == "0")
+      raise "BucketNotEmpty" unless bucket.blob_list.empty?
       @client.destroy(:buckets, bucket.id)
     end
 
@@ -427,7 +427,7 @@ module Deltacloud::Drivers::Mock
     #--
     def blob_metadata(credentials, opts={})
       check_credentials(credentials)
-      if blob = @client.load(:blobs, params[:id])
+      if blob = @client.load(:blobs, opts[:id])
         blob[:user_metadata]
       else
         nil
@@ -440,7 +440,7 @@ module Deltacloud::Drivers::Mock
     def update_blob_metadata(credentials, opts={})
       check_credentials(credentials)
       safely do
-        blob = @client.load(:blobs, params[:id])
+        blob = @client.load(:blobs, opts[:id])
         return false unless blob
         blob[:user_metadata] = BlobHelper::rename_metadata_headers(opts['meta_hash'], '')
         @client.store(:blobs, blob)
diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb b/server/lib/deltacloud/helpers/deltacloud_helper.rb
index 83741f9..ee9decc 100644
--- a/server/lib/deltacloud/helpers/deltacloud_helper.rb
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -230,6 +230,8 @@ module Deltacloud::Helpers
       end
     end
 
+    NEW_BLOB_FORM_ID = 'new_blob_form_d15cfd90'
+
     def new_blob_form_url(bucket)
       bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
     end
diff --git a/server/lib/deltacloud/helpers/url_helper.rb b/server/lib/deltacloud/helpers/url_helper.rb
index 87bc93e..fd71f43 100644
--- a/server/lib/deltacloud/helpers/url_helper.rb
+++ b/server/lib/deltacloud/helpers/url_helper.rb
@@ -33,8 +33,11 @@ module Sinatra
       if name.to_s =~ /^([\w\_]+)_url$/
         if args.size > 0
           t = $1
-          if t =~ /^(stop|reboot|destroy|start|attach|detach)_/
-            api_url_for(t.pluralize.split('_').last + '/' + args.first + '/' + $1, :full)
+          if t.match(/^(stop|reboot|start|attach|detach)_/)
+            action = $1
+            api_url_for(t.pluralize.split('_').last + '/' + args.first + '/' + action, :full)
+          elsif t.match(/^(destroy|update)_/)
+            api_url_for(t.pluralize.split('_').last + '/' + args.first, :full)
           else
             api_url_for(t.pluralize, :full) + '/' + "#{args.first}"
           end
diff --git a/server/lib/deltacloud/models/bucket.rb b/server/lib/deltacloud/models/bucket.rb
index b1551b7..0c21c21 100644
--- a/server/lib/deltacloud/models/bucket.rb
+++ b/server/lib/deltacloud/models/bucket.rb
@@ -22,6 +22,10 @@ class Bucket < BaseModel
 
   alias :to_hash_original :to_hash
 
+  def blob_list
+    @blob_list || []
+  end
+
   def to_hash
     h = self.to_hash_original
     unless blob_list.nil?
diff --git a/server/views/buckets/new.html.haml b/server/views/buckets/new.html.haml
index 2abaa96..bc0f0c3 100644
--- a/server/views/buckets/new.html.haml
+++ b/server/views/buckets/new.html.haml
@@ -6,7 +6,7 @@
       Bucket Name:
       %input{ :name => 'name', :size => 250}/
       %br
-    -if driver_has_feature?(:bucket_location, :buckets)
+    -if driver.class.has_feature?(:bucket_location, :buckets)
       %p
         %label
           Location: (optional)
-- 
1.7.10.1


[PATCH core 22/51] Tests: Fixed mock Cucumber tests to work for Sinatra::Base

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/helpers/deltacloud_helper.rb |    5 +++
 server/lib/deltacloud/helpers/url_helper.rb        |    4 +--
 server/lib/deltacloud/models/instance.rb           |    4 +++
 server/views/instances/show.xml.haml               |    4 +--
 tests/ec2/api.feature                              |    3 +-
 tests/ec2/step_definitions/api_steps.rb            |   37 ++++++++++----------
 tests/ec2/support/env.rb                           |   31 ++++++++--------
 tests/mock/api.feature                             |    1 -
 tests/mock/images.feature                          |    2 ++
 tests/mock/step_definitions/images_steps.rb        |   14 ++++----
 tests/mock/storage_snapshots.feature               |    1 +
 11 files changed, 58 insertions(+), 48 deletions(-)

diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb b/server/lib/deltacloud/helpers/deltacloud_helper.rb
index ee9decc..2fc2a59 100644
--- a/server/lib/deltacloud/helpers/deltacloud_helper.rb
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -26,6 +26,11 @@ module Deltacloud::Helpers
       end
     end
 
+    def auth_feature_name
+      return 'key' if driver.class.has_feature?(:instances, :authentication_key)
+      return 'password' if driver.class.has_feature?(:instances, :authentication_password)
+    end
+
     def instance_action_method(action)
       action_method(action, Sinatra::Rabbit::InstancesCollection)
     end
diff --git a/server/lib/deltacloud/helpers/url_helper.rb b/server/lib/deltacloud/helpers/url_helper.rb
index fd71f43..b35c714 100644
--- a/server/lib/deltacloud/helpers/url_helper.rb
+++ b/server/lib/deltacloud/helpers/url_helper.rb
@@ -79,7 +79,7 @@ module Sinatra
     def url_for url_fragment, mode=:path_only
       case mode
       when :path_only
-        base = request.script_name
+        base = request.script_name.empty? ? API_ROOT_URL : request.script_name
       when :full
         scheme = request.scheme
         port = request.port
@@ -96,7 +96,7 @@ module Sinatra
         else
           port = ":#{port}"
         end
-        base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
+        base = "#{scheme}://#{request_host}#{port}#{request.script_name.empty? ? API_ROOT_URL : request.script_name}"
       else
         raise TypeError, "Unknown url_for mode #{mode}"
       end
diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index c2cc0e3..9db5b4b 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -34,6 +34,10 @@ class Instance < BaseModel
   attr_accessor :firewalls
   attr_accessor :storage_volumes
 
+  def storage_volumes
+    @storage_volumes || []
+  end
+
   def can_create_image?
     self.create_image
   end
diff --git a/server/views/instances/show.xml.haml b/server/views/instances/show.xml.haml
index 3a62ed3..a91c0c5 100644
--- a/server/views/instances/show.xml.haml
+++ b/server/views/instances/show.xml.haml
@@ -45,8 +45,8 @@
     %storage_volumes<
       - @instance.storage_volumes.each do |volume|
         %storage_volume{:href=> storage_volume_url(volume.keys.first), :id => volume.keys.first, :device => volume.values.first}
-  - if driver.class.has_feature?(:authentication_key) or driver.class.has_feature?(:authentication_password)
-    %authentication{ :type => driver_auth_feature_name }
+  - if driver.class.has_feature?(:instances, :authentication_key) or driver.class.has_feature?(:instances, :authentication_password)
+    %authentication{ :type => auth_feature_name }
       - if @instance.authn_feature_failed?
         %error  #{@instance.authn_error}
       - else
diff --git a/tests/ec2/api.feature b/tests/ec2/api.feature
index 2dcd1b2..9d53722 100644
--- a/tests/ec2/api.feature
+++ b/tests/ec2/api.feature
@@ -26,6 +26,7 @@ Feature: Accessing API entry points
     | storage_volumes    |
     | addresses |
     | firewalls |
+    | metrics |
     And this URI should be available in XML, JSON, HTML format
 
   Scenario: Following entry points
@@ -46,6 +47,7 @@ Feature: Accessing API entry points
     | storage_volumes    |
     | addresses |
     | firewalls |
+    | metrics |
     And each link should have 'rel' attribute with valid name
     And each link should have 'href' attribute with valid URL
     When client follow this attribute
@@ -61,4 +63,3 @@ Feature: Accessing API entry points
     | user_data |
     | instance_count |
     | firewalls |
-    | hardware_profiles |
diff --git a/tests/ec2/step_definitions/api_steps.rb b/tests/ec2/step_definitions/api_steps.rb
index c42af6f..27172e8 100644
--- a/tests/ec2/step_definitions/api_steps.rb
+++ b/tests/ec2/step_definitions/api_steps.rb
@@ -8,11 +8,11 @@ end
 Given /^URI ([\w\/\-_]+) exists in (.+) format$/ do |uri, format|
   @uri = uri
   case format.downcase
-    when 'xml':
+    when 'xml' then
       header 'Accept', 'application/xml;q=9'
-    when 'json'
+    when 'json' then
       header 'Accept', 'application/json;q=9'
-    when 'html'
+    when 'html' then
       header 'Accept', 'application/xml+xhtml;q=9'
   end
   get @uri, {}
@@ -52,11 +52,11 @@ Then /^this URI should be available in (.+) format$/ do |formats|
   @no_header = true
   formats.split(',').each do |format|
     case format.downcase
-    when 'xml':
+    when 'xml' then
       header 'Accept', 'application/xml;q=9'
-    when 'json'
+    when 'json' then
       header 'Accept', 'application/json;q=9'
-    when 'html'
+    when 'html' then
       header 'Accept', 'application/xml+xhtml;q=9'
     end
     get @uri, {}
@@ -75,15 +75,15 @@ end
 
 Then /^each (\w+) should have '(.+)' attribute with valid (.+)$/ do |el, attr, t|
   case el
-    when 'link':
+    when 'link' then
       path = '/api/link'
-    when 'image':
+    when 'image' then
       path = '/images/image'
-    when 'instance':
+    when 'instance' then
       path = '/instances/instance'
-    when 'key':
+    when 'key' then
       path = '/keys/key'
-    when 'realm':
+    when 'realm' then
       path = '/realms/realm'
   end
   output_xml.xpath(path).each do |entry_point|
@@ -97,11 +97,11 @@ end
 
 Then /^each ([\w\-]+) should have '(.+)' attribute set to '(.+)'$/ do |el, attr, v|
   case el
-    when 'image':
+    when 'image' then
       path = "/images/image"
-    when 'hardware_profile':
+    when 'hardware_profile' then
       path = "/hardware_profiles/hardware_profile"
-    when 'instance':
+    when 'instance' then
       path = "/instances/instance"
   end
   output_xml.xpath(path).each do |element|
@@ -111,11 +111,11 @@ end
 
 Then /^each ([\w\-]+) should have '(.+)' element set to '(.+)'$/ do |el, child, v|
   case el
-    when 'image':
+    when 'image' then
       path = "/images/image"
-    when 'hardware_profile':
+    when 'hardware_profile' then
       path = "/hardware_profiles/hardware_profile"
-    when 'instance':
+    when 'instance' then
       path = "/instances/instance"
   end
   output_xml.xpath(path).each do |element|
@@ -126,7 +126,7 @@ end
 
 Then /^each ([\w\-]+) should have '(.+)' property set to '(.+)'$/ do |el, property, v|
   case el
-    when 'hardware_profile':
+    when 'hardware_profile' then
       path = "/hardware_profiles/hardware_profile"
   end
   output_xml.xpath(path).each do |element|
@@ -143,6 +143,7 @@ When /^client follow this attribute$/ do
 end
 
 Then /^client should get a valid response$/ do
+  puts last_response.body
   last_response.status.should_not == 500
 end
 
diff --git a/tests/ec2/support/env.rb b/tests/ec2/support/env.rb
index 5245bb1..5eb006a 100644
--- a/tests/ec2/support/env.rb
+++ b/tests/ec2/support/env.rb
@@ -1,21 +1,20 @@
-SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
+require 'rubygems'
+require 'nokogiri'
 
+SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
 $top_srcdir = SERVER_DIR
 $:.unshift File::join($top_srcdir, 'lib')
-
 Dir.chdir(SERVER_DIR)
 
-ENV['API_DRIVER'] = 'ec2'
+API_VERSION = "9.9.9"
+API_ROOT_URL = "/api"
 
-require 'rubygems'
-require 'nokogiri'
-require 'deltacloud/server'
-require 'rack/test'
+ENV['API_DRIVER'] = 'ec2'
+ENV.delete('API_VERBOSE')
 
-Sinatra::Application.set :environment, :test
-Sinatra::Application.set :root, SERVER_DIR
+load File.join($top_srcdir, 'lib', 'deltacloud', 'server.rb')
 
-require '../server/lib/deltacloud/base_driver/mock_driver'
+require 'rack/test'
 
 CONFIG = {
   :username => 'mockuser',
@@ -26,13 +25,11 @@ World do
   include Rack::Test::Methods
 
   def app
-    @app = Rack::Builder.new do
-      set :environment => :test
-      set :loggining => true
-      set :raise_errors => true
-      set :show_exceptions => false
-      run Sinatra::Application
-    end
+    @app = Rack::URLMap.new(
+      "/" => Deltacloud::API.new,
+      "/stylesheets" =>  Rack::Directory.new( "public/stylesheets" ),
+      "/javascripts" =>  Rack::Directory.new( "public/javascripts" )
+    )
   end
 
   def output_xml
diff --git a/tests/mock/api.feature b/tests/mock/api.feature
index d7fb044..59d00d1 100644
--- a/tests/mock/api.feature
+++ b/tests/mock/api.feature
@@ -53,4 +53,3 @@ Feature: Accessing API entry points
     | user_name |
     | user_data |
     | authentication_key |
-    | hardware_profiles |
diff --git a/tests/mock/images.feature b/tests/mock/images.feature
index 0bae93d..0094548 100644
--- a/tests/mock/images.feature
+++ b/tests/mock/images.feature
@@ -12,6 +12,7 @@ Feature: Listing and showing images
     | architecture |
     | owner_id |
     | state |
+    | hardware_profiles |
     | actions |
     And each image should have 'href' attribute with valid URL
     And this URI should be available in XML, JSON, HTML format
@@ -29,6 +30,7 @@ Feature: Listing and showing images
     | name |
     | description |
     | architecture |
+    | hardware_profiles |
     | owner_id |
     | state |
     | actions |
diff --git a/tests/mock/step_definitions/images_steps.rb b/tests/mock/step_definitions/images_steps.rb
index 323778c..46963bb 100644
--- a/tests/mock/step_definitions/images_steps.rb
+++ b/tests/mock/step_definitions/images_steps.rb
@@ -27,17 +27,17 @@ end
 
 When /^client want to show first (.+)$/ do |element|
   case element
-    when 'image':
+    when 'image' then
       path = '/images/image'
-    when 'instance':
+    when 'instance' then
       path = '/instances/instance'
-    when 'realm':
+    when 'realm' then
       path = '/realms/realm'
-    when 'hardware_profile'
+    when 'hardware_profile' then
       path = '/hardware_profiles/hardware_profile'
-    when 'storage_volume':
+    when 'storage_volume' then
       path = '/storage_volumes/storage_volume'
-    when 'storage_snapshot':
+    when 'storage_snapshot' then
       path = '/storage_snapshots/storage_snapshot'
   end
   @element = output_xml.xpath(path).first
@@ -58,7 +58,7 @@ Then /^client follow (\w+) attribute in first (.+)$/ do |attr, el|
 end
 
 Then /^client should get this (.+)$/ do |el|
-  last_response.status.should == 200
+  last_response.status.to_s =~ /2(\d{2})/
 end
 
 
diff --git a/tests/mock/storage_snapshots.feature b/tests/mock/storage_snapshots.feature
index fdaff9c..350a2a3 100644
--- a/tests/mock/storage_snapshots.feature
+++ b/tests/mock/storage_snapshots.feature
@@ -23,4 +23,5 @@ Feature: Accessing storage snapshots
     Then client should get this storage_snapshot
     And this storage_snapshot should have:
     | created |
+    | name |
     | storage_volume |
-- 
1.7.10.1


[PATCH core 28/51] Core: Load core_ext in deltacloud_rack to make them available in all frontends

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud.rb         |    3 +--
 server/lib/deltacloud/helpers.rb |    6 +-----
 server/lib/deltacloud_rack.rb    |   14 ++++++++++++++
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/server/lib/deltacloud.rb b/server/lib/deltacloud.rb
index 6508d8d..6160cce 100644
--- a/server/lib/deltacloud.rb
+++ b/server/lib/deltacloud.rb
@@ -14,11 +14,10 @@
 # under the License.
 
 require 'rubygems'
+require 'ostruct'
 
 load File.join(File.dirname(__FILE__), 'deltacloud/core_ext.rb')
 
-require 'ostruct'
-
 require_relative 'deltacloud/core_ext/string'
 require_relative 'deltacloud/core_ext/array'
 require_relative 'deltacloud/core_ext/hash'
diff --git a/server/lib/deltacloud/helpers.rb b/server/lib/deltacloud/helpers.rb
index b4f859f..2109362 100644
--- a/server/lib/deltacloud/helpers.rb
+++ b/server/lib/deltacloud/helpers.rb
@@ -19,11 +19,7 @@ require_relative 'helpers/url_helper'
 require_relative 'helpers/deltacloud_helper'
 require_relative 'helpers/rabbit_helper'
 require_relative 'helpers/blob_stream_helper'
-require_relative 'core_ext/string'
-require_relative 'core_ext/array'
-require_relative 'core_ext/hash'
-require_relative 'core_ext/integer'
-require_relative 'core_ext/proc'
+
 
 module Deltacloud::Collections
   class Base < Sinatra::Base
diff --git a/server/lib/deltacloud_rack.rb b/server/lib/deltacloud_rack.rb
index 873ef29..b795731 100644
--- a/server/lib/deltacloud_rack.rb
+++ b/server/lib/deltacloud_rack.rb
@@ -13,6 +13,20 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+unless Kernel.respond_to?(:require_relative)
+  module Kernel
+    def require_relative(path)
+      require File.join(File.dirname(caller[0]), path.to_str)
+    end
+  end
+end
+
+require_relative './deltacloud/core_ext/string'
+require_relative './deltacloud/core_ext/array'
+require_relative './deltacloud/core_ext/hash'
+require_relative './deltacloud/core_ext/integer'
+require_relative './deltacloud/core_ext/proc'
+
 module Deltacloud
 
   def self.config(conf=nil)
-- 
1.7.10.1


[PATCH core 19/51] Core: Fixed wrong brackets in response_to block under load_balancers

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/load_balancers.rb |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/server/lib/deltacloud/collections/load_balancers.rb b/server/lib/deltacloud/collections/load_balancers.rb
index d093ead..f6fbc62 100644
--- a/server/lib/deltacloud/collections/load_balancers.rb
+++ b/server/lib/deltacloud/collections/load_balancers.rb
@@ -48,7 +48,7 @@ module Deltacloud::Collections
           @load_balancer = driver.load_balancer(credential, params[:id])
           respond_to do |format|
             format.xml { haml :'load_balancers/show' }
-            format.json ( xml_to_json('load_balancers/show'))
+            format.json { xml_to_json('load_balancers/show') }
             format.html { haml :'load_balancers/show' }
           end
         end
@@ -61,7 +61,7 @@ module Deltacloud::Collections
           @load_balancer = driver.load_balancer(credential, params[:id])
           respond_to do |format|
             format.xml { haml :'load_balancers/show' }
-            format.json ( xml_to_json('load_balancers/show'))
+            format.json { xml_to_json('load_balancers/show')}
             format.html { haml :'load_balancers/show' }
           end
         end
-- 
1.7.10.1


[PATCH core 48/51] Tests: Make possible to run each test separately and fixed openstack and rackspace tests

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Rakefile                                    |    4 +--
 server/lib/deltacloud/drivers/features.rb          |    7 ++++
 server/tests/drivers/google/api_test.rb            |    3 ++
 server/tests/drivers/google/buckets_test.rb        |    3 ++
 server/tests/drivers/google/common.rb              |   36 +-------------------
 server/tests/drivers/mock/api_test.rb              |    3 ++
 server/tests/drivers/mock/buckets_test.rb          |    3 ++
 server/tests/drivers/mock/common.rb                |    1 +
 server/tests/drivers/mock/drivers_test.rb          |    3 ++
 .../tests/drivers/mock/hardware_profiles_test.rb   |    3 ++
 server/tests/drivers/mock/images_test.rb           |    3 ++
 server/tests/drivers/mock/instances_test.rb        |    3 ++
 server/tests/drivers/mock/keys_test.rb             |    3 ++
 server/tests/drivers/mock/realms_test.rb           |    3 ++
 .../tests/drivers/mock/storage_snapshots_test.rb   |    3 ++
 server/tests/drivers/mock/storage_volumes_test.rb  |    3 ++
 server/tests/drivers/openstack/api_test.rb         |    6 ++--
 server/tests/drivers/openstack/common.rb           |   21 ++++++++++++
 .../drivers/openstack/hardware_profiles_test.rb    |    2 +-
 server/tests/drivers/openstack/images_test.rb      |    2 +-
 server/tests/drivers/openstack/instances_test.rb   |    6 ++--
 server/tests/drivers/openstack/realms_test.rb      |    2 +-
 server/tests/drivers/openstack/setup.rb            |   20 -----------
 server/tests/drivers/rackspace/api_test.rb         |    9 +++--
 server/tests/drivers/rackspace/buckets_test.rb     |    9 +++--
 server/tests/drivers/rackspace/common.rb           |   16 +++++++++
 .../drivers/rackspace/hardware_profiles_test.rb    |    9 +++--
 server/tests/drivers/rackspace/images_test.rb      |    9 +++--
 server/tests/drivers/rackspace/instances_test.rb   |   15 +++++---
 server/tests/drivers/rackspace/realms_test.rb      |    9 +++--
 server/tests/drivers/rackspace/setup.rb            |   14 --------
 server/tests/drivers/rhevm/api_test.rb             |    4 +--
 server/tests/drivers/rhevm/common.rb               |   12 ++++++-
 .../tests/drivers/rhevm/hardware_profiles_test.rb  |    3 +-
 server/tests/drivers/rhevm/images_test.rb          |    4 +--
 server/tests/drivers/rhevm/instances_test.rb       |    3 +-
 server/tests/drivers/rhevm/realms_test.rb          |    4 +--
 37 files changed, 154 insertions(+), 109 deletions(-)
 delete mode 100644 server/tests/drivers/openstack/setup.rb
 create mode 100644 server/tests/drivers/rackspace/common.rb
 delete mode 100644 server/tests/drivers/rackspace/setup.rb

diff --git a/server/Rakefile b/server/Rakefile
index c9ef650..8223e5e 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -229,9 +229,7 @@ namespace :test do
   %w(mock rackspace rhevm openstack google fgcp).each do |driver|
     desc "Run #{driver} unit tests"
     Rake::TestTask.new(driver) { |t|
-      Rake::Task["mock:fixtures:reset"].invoke
-      t.test_files = ['tests/drivers/'+driver+'/common.rb'] + FileList.new("tests/drivers/#{driver}/*_test.rb")
-      t.options = "-v -v"
+      t.test_files = FileList.new("tests/drivers/#{driver}/*_test.rb")
       t.verbose = true
       t.warning = false
     }
diff --git a/server/lib/deltacloud/drivers/features.rb b/server/lib/deltacloud/drivers/features.rb
index c772a42..c2af8cb 100644
--- a/server/lib/deltacloud/drivers/features.rb
+++ b/server/lib/deltacloud/drivers/features.rb
@@ -72,6 +72,13 @@ module Deltacloud
         end
       end
 
+      feature :user_files, :for => :instances do
+        description "Allow to pass user files into the instance"
+        operation :create do
+          param :user_files, :string, :optional
+        end
+      end
+
       feature :user_iso, :for => :instances do
         description  "Base64 encoded gzipped ISO file will be accessible as CD-ROM drive in instance"
         operation :create do
diff --git a/server/tests/drivers/google/api_test.rb b/server/tests/drivers/google/api_test.rb
index 88ff74d..3bb53ef 100644
--- a/server/tests/drivers/google/api_test.rb
+++ b/server/tests/drivers/google/api_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/google/common'
+
 module GoogleTest
 
   class ApiTest < Test::Unit::TestCase
diff --git a/server/tests/drivers/google/buckets_test.rb b/server/tests/drivers/google/buckets_test.rb
index dac8c87..14a953f 100644
--- a/server/tests/drivers/google/buckets_test.rb
+++ b/server/tests/drivers/google/buckets_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/google/common'
+
 module GoogleTest
 
   class BucketsTest < Test::Unit::TestCase
diff --git a/server/tests/drivers/google/common.rb b/server/tests/drivers/google/common.rb
index d9da302..ea008e2 100644
--- a/server/tests/drivers/google/common.rb
+++ b/server/tests/drivers/google/common.rb
@@ -3,6 +3,7 @@ ENV['API_USER']     = 'GOOGK7JXLS6UEYS6AYVO'
 ENV['API_PASSWORD'] = 'QjxUunLgszKhBGn/LISQajGR82CfwvraxA9lqnkg'
 
 load File.join(File.dirname(__FILE__), '..', '..', 'common.rb')
+
 require 'vcr'
 
 DeltacloudTestCommon::record!
@@ -37,38 +38,3 @@ module VCR
     end
   end
 end
-
-module Deltacloud
-  module Test
-    include Rack::Test::Methods
-
-    def included?(sub)
-      sub.class_eval do
-        before do
-          header 'Accept', 'application/xml'
-        end
-      end
-    end
-
-    def xml_response
-      Nokogiri::XML(last_response.body)
-    end
-
-    def auth_as_mock
-      authorize ENV['API_USERNAME'], ENV['API_PASSWORD']
-    end
-
-    def collection_url(collection)
-      [Deltacloud[:root_url], collection.to_s].join('/')
-    end
-
-    def app
-      Rack::Builder.new {
-        map '/' do
-          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
-          run Rack::Cascade.new([Deltacloud::API])
-        end
-      }
-    end
-  end
-end
diff --git a/server/tests/drivers/mock/api_test.rb b/server/tests/drivers/mock/api_test.rb
index cafe0be..f8174b7 100644
--- a/server/tests/drivers/mock/api_test.rb
+++ b/server/tests/drivers/mock/api_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/buckets_test.rb b/server/tests/drivers/mock/buckets_test.rb
index 91970ff..d05a5fe 100644
--- a/server/tests/drivers/mock/buckets_test.rb
+++ b/server/tests/drivers/mock/buckets_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API buckets' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/common.rb b/server/tests/drivers/mock/common.rb
index 2610965..a55c44f 100644
--- a/server/tests/drivers/mock/common.rb
+++ b/server/tests/drivers/mock/common.rb
@@ -1,3 +1,4 @@
+ENV['API_DRIVER']   = 'mock'
 ENV['API_USERNAME'] = 'mockuser'
 ENV['API_PASSWORD'] = 'mockpassword'
 
diff --git a/server/tests/drivers/mock/drivers_test.rb b/server/tests/drivers/mock/drivers_test.rb
index 9e5bc71..537c341 100644
--- a/server/tests/drivers/mock/drivers_test.rb
+++ b/server/tests/drivers/mock/drivers_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API drivers' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/hardware_profiles_test.rb b/server/tests/drivers/mock/hardware_profiles_test.rb
index aed2a04..1af59ef 100644
--- a/server/tests/drivers/mock/hardware_profiles_test.rb
+++ b/server/tests/drivers/mock/hardware_profiles_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API Hardware Profiles' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/images_test.rb b/server/tests/drivers/mock/images_test.rb
index 909fdf1..0ab8db1 100644
--- a/server/tests/drivers/mock/images_test.rb
+++ b/server/tests/drivers/mock/images_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API Images' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/instances_test.rb b/server/tests/drivers/mock/instances_test.rb
index 878589c..d44fac5 100644
--- a/server/tests/drivers/mock/instances_test.rb
+++ b/server/tests/drivers/mock/instances_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API instances' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/keys_test.rb b/server/tests/drivers/mock/keys_test.rb
index 2738a50..51d385b 100644
--- a/server/tests/drivers/mock/keys_test.rb
+++ b/server/tests/drivers/mock/keys_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API Keys' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/realms_test.rb b/server/tests/drivers/mock/realms_test.rb
index 5496bc4..1540252 100644
--- a/server/tests/drivers/mock/realms_test.rb
+++ b/server/tests/drivers/mock/realms_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API Realms' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/storage_snapshots_test.rb b/server/tests/drivers/mock/storage_snapshots_test.rb
index 70ac2ba..2df56cb 100644
--- a/server/tests/drivers/mock/storage_snapshots_test.rb
+++ b/server/tests/drivers/mock/storage_snapshots_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API storage_snapshots' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/mock/storage_volumes_test.rb b/server/tests/drivers/mock/storage_volumes_test.rb
index efceaee..7c41d38 100644
--- a/server/tests/drivers/mock/storage_volumes_test.rb
+++ b/server/tests/drivers/mock/storage_volumes_test.rb
@@ -1,3 +1,6 @@
+$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
+require 'tests/drivers/mock/common'
+
 describe 'Deltacloud API storage_volumes' do
   include Deltacloud::Test
 
diff --git a/server/tests/drivers/openstack/api_test.rb b/server/tests/drivers/openstack/api_test.rb
index b9c3fb2..e254060 100644
--- a/server/tests/drivers/openstack/api_test.rb
+++ b/server/tests/drivers/openstack/api_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/openstack/common'
 
 module OpenstackTest
 
@@ -36,10 +36,10 @@ module OpenstackTest
       collections.include?('instance_states').should == true
       collections.include?('instances').should == true
       collections.include?('images').should == true
-#      collections.include?('buckets').should == true # NOT YET IMPLEMENTED FOR V2 driver
+      collections.include?('buckets').should == true # NOT YET IMPLEMENTED FOR V2 driver
       collections.include?('realms').should == true
       collections.include?('hardware_profiles').should == true
-      collections.length.should == 6 #7
+      collections.length.should == 7
     end
 
   end
diff --git a/server/tests/drivers/openstack/common.rb b/server/tests/drivers/openstack/common.rb
index e69de29..595eed7 100644
--- a/server/tests/drivers/openstack/common.rb
+++ b/server/tests/drivers/openstack/common.rb
@@ -0,0 +1,21 @@
+ENV['API_DRIVER']   = "openstack"
+ENV['API_USER']     = 'foo@bar.com+foo@bar.com-default-tenant'
+ENV['API_PASSWORD'] = 'Not_a_real_password!1'
+ENV['API_PROVIDER'] = 'https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/'
+
+load File.join(File.dirname(__FILE__), '..', '..', 'common.rb')
+require 'vcr'
+
+DeltacloudTestCommon::record!
+
+VCR.config do |c|
+  c.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures')
+  c.stub_with :webmock
+  c.default_cassette_options = { :record => :none }
+end
+
+class WebMock::Config
+  def net_http_connect_on_start
+    true
+  end
+end
diff --git a/server/tests/drivers/openstack/hardware_profiles_test.rb b/server/tests/drivers/openstack/hardware_profiles_test.rb
index 68a4f0c..1225e01 100644
--- a/server/tests/drivers/openstack/hardware_profiles_test.rb
+++ b/server/tests/drivers/openstack/hardware_profiles_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/openstack/common'
 
 module OpenstackTest
 
diff --git a/server/tests/drivers/openstack/images_test.rb b/server/tests/drivers/openstack/images_test.rb
index 3049364..bec7b27 100644
--- a/server/tests/drivers/openstack/images_test.rb
+++ b/server/tests/drivers/openstack/images_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/openstack/common'
 
 module OpenstackTest
 
diff --git a/server/tests/drivers/openstack/instances_test.rb b/server/tests/drivers/openstack/instances_test.rb
index d7da173..3422b59 100644
--- a/server/tests/drivers/openstack/instances_test.rb
+++ b/server/tests/drivers/openstack/instances_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/openstack/common'
 
 module OpenstackTest
 
@@ -171,7 +171,7 @@ module OpenstackTest
         :'api[driver]' => 'openstack',
       }
       post_url "/api/instances/#{(@@instance/'instance').first[:id]}/stop", params
-      last_response.status.should == 200
+      last_response.status.should == 202
       20.times do |tick|
         get_auth_url "/api;driver=openstack/instances/#{(@@instance/'instance').first[:id]}", { :tick => tick}
         last_response.status.should_not == 500
@@ -195,7 +195,7 @@ module OpenstackTest
         :'api[driver]' => 'openstack',
       }
       post_url "/api/instances/#{(@@instance2/'instance').first[:id]}/stop", params
-      last_response.status.should == 200
+      last_response.status.should == 202
       20.times do |tick|
         get_auth_url "/api;driver=openstack/instances/#{(@@instance2/'instance').first[:id]}", { :tick => tick}
         last_response.status.should_not == 500
diff --git a/server/tests/drivers/openstack/realms_test.rb b/server/tests/drivers/openstack/realms_test.rb
index 613e5ec..82be205 100644
--- a/server/tests/drivers/openstack/realms_test.rb
+++ b/server/tests/drivers/openstack/realms_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/openstack/common'
 
 module OpenstackTest
 
diff --git a/server/tests/drivers/openstack/setup.rb b/server/tests/drivers/openstack/setup.rb
deleted file mode 100644
index b9e1ca0..0000000
--- a/server/tests/drivers/openstack/setup.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-ENV.delete 'API_VERBOSE'
-ENV['API_DRIVER']   = "openstack"
-ENV['API_USER']     = 'foo@bar.com+foo@bar.com-default-tenant'
-ENV['API_PASSWORD'] = 'Not_a_real_password!1'
-ENV['API_PROVIDER'] = 'https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/'
-
-require 'vcr'
-DeltacloudTestCommon::record!
-
-VCR.config do |c|
-  c.cassette_library_dir = "#{File.dirname(__FILE__)}/../../../tests/drivers/openstack/fixtures/"
-  c.stub_with :webmock
-  c.default_cassette_options = { :record => :new_episodes }
-end
-
-class WebMock::Config
-  def net_http_connect_on_start
-    true
-  end
-end
diff --git a/server/tests/drivers/rackspace/api_test.rb b/server/tests/drivers/rackspace/api_test.rb
index 802bfb8..33634d7 100644
--- a/server/tests/drivers/rackspace/api_test.rb
+++ b/server/tests/drivers/rackspace/api_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rackspace/common'
 
 module RackspaceTest
 
@@ -7,7 +7,12 @@ module RackspaceTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_entry_points
diff --git a/server/tests/drivers/rackspace/buckets_test.rb b/server/tests/drivers/rackspace/buckets_test.rb
index c4b0de0..9640937 100644
--- a/server/tests/drivers/rackspace/buckets_test.rb
+++ b/server/tests/drivers/rackspace/buckets_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rackspace/common'
 #require 'webmock/test_unit'
 module RackspaceTest
 
@@ -7,7 +7,12 @@ module RackspaceTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     @@created_bucket_name="testbucki2rpux3wdelme"
diff --git a/server/tests/drivers/rackspace/common.rb b/server/tests/drivers/rackspace/common.rb
new file mode 100644
index 0000000..b8e1de5
--- /dev/null
+++ b/server/tests/drivers/rackspace/common.rb
@@ -0,0 +1,16 @@
+load File.join(File.dirname(__FILE__), '..', '..', 'common.rb')
+
+ENV['API_DRIVER']   = "rackspace"
+ENV['API_USER']     = 'mandreou'
+ENV['API_PASSWORD'] = 'a4d531ef02a37dd32cac1e8e516df9eb'
+
+require 'vcr'
+
+DeltacloudTestCommon::record!
+
+VCR.config do |c|
+  c.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures')
+  c.stub_with :webmock
+  c.default_cassette_options = { :record => :none }
+end
+
diff --git a/server/tests/drivers/rackspace/hardware_profiles_test.rb b/server/tests/drivers/rackspace/hardware_profiles_test.rb
index 2cd6418..f1e6bc5 100644
--- a/server/tests/drivers/rackspace/hardware_profiles_test.rb
+++ b/server/tests/drivers/rackspace/hardware_profiles_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rackspace/common'
 
 module RackspaceTest
 
@@ -7,7 +7,12 @@ module RackspaceTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_hardware_profiles
diff --git a/server/tests/drivers/rackspace/images_test.rb b/server/tests/drivers/rackspace/images_test.rb
index 5bb2cc8..964caa1 100644
--- a/server/tests/drivers/rackspace/images_test.rb
+++ b/server/tests/drivers/rackspace/images_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rackspace/common'
 
 module RackspaceTest
 
@@ -7,7 +7,12 @@ module RackspaceTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_images
diff --git a/server/tests/drivers/rackspace/instances_test.rb b/server/tests/drivers/rackspace/instances_test.rb
index f185625..8d06280 100644
--- a/server/tests/drivers/rackspace/instances_test.rb
+++ b/server/tests/drivers/rackspace/instances_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rackspace/common'
 
 module RackspaceTest
 
@@ -7,7 +7,12 @@ module RackspaceTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_01_it_can_create_instance_without_hardware_profile
@@ -118,7 +123,7 @@ module RackspaceTest
         :'api[driver]' => 'rackspace',
       }
       post_url "/api/instances/#{(@@instance/'instance').first[:id]}/reboot", params
-      last_response.status.should == 200
+      last_response.status.should == 202
       20.times do |tick|
         get_auth_url "/api;driver=rackspace/instances/#{(@@instance/'instance').first[:id]}", { :tick => tick}
         last_response.status.should_not == 500
@@ -133,7 +138,7 @@ module RackspaceTest
         :'api[driver]' => 'rackspace',
       }
       post_url "/api/instances/#{(@@instance/'instance').first[:id]}/stop", params
-      last_response.status.should == 200
+      last_response.status.should == 202
       20.times do |tick|
         get_auth_url "/api;driver=rackspace/instances/#{(@@instance/'instance').first[:id]}", { :tick => tick}
         last_response.status.should_not == 500
@@ -148,7 +153,7 @@ module RackspaceTest
         :'api[driver]' => 'rackspace',
       }
       post_url "/api/instances/#{(@@instance2/'instance').first[:id]}/stop", params, authenticate
-      last_response.status.should == 200
+      last_response.status.should == 202
       20.times do |tick|
         get_auth_url "/api;driver=rackspace/instances/#{(@@instance2/'instance').first[:id]}", { :tick => tick}
         last_response.status.should_not == 500
diff --git a/server/tests/drivers/rackspace/realms_test.rb b/server/tests/drivers/rackspace/realms_test.rb
index 9a01898..d221136 100644
--- a/server/tests/drivers/rackspace/realms_test.rb
+++ b/server/tests/drivers/rackspace/realms_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rackspace/common'
 
 module RackspaceTest
 
@@ -7,7 +7,12 @@ module RackspaceTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_realms
diff --git a/server/tests/drivers/rackspace/setup.rb b/server/tests/drivers/rackspace/setup.rb
deleted file mode 100644
index 46c3919..0000000
--- a/server/tests/drivers/rackspace/setup.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-ENV['API_DRIVER']   = "rackspace"
-ENV['API_USER']     = 'mandreou'
-ENV['API_PASSWORD'] = 'a4d531ef02a37dd32cac1e8e516df9eb'
-
-require 'vcr'
-
-DeltacloudTestCommon::record!
-
-VCR.config do |c|
-  c.cassette_library_dir = "#{File.dirname(__FILE__)}/../../../tests/drivers/rackspace/fixtures/"
-  c.stub_with :webmock
-  c.default_cassette_options = { :record => :new_episodes }
-end
-
diff --git a/server/tests/drivers/rhevm/api_test.rb b/server/tests/drivers/rhevm/api_test.rb
index 0d8d69e..8c6e554 100644
--- a/server/tests/drivers/rhevm/api_test.rb
+++ b/server/tests/drivers/rhevm/api_test.rb
@@ -1,5 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rhevm/common'
 
 module RHEVMTest
 
@@ -8,8 +8,6 @@ module RHEVMTest
 
     def app
       Rack::Builder.new {
-        use Rack::MatrixParams
-        use Rack::DriverSelect
         map '/' do
           use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
           run Rack::Cascade.new([Deltacloud::API])
diff --git a/server/tests/drivers/rhevm/common.rb b/server/tests/drivers/rhevm/common.rb
index 1ab0f99..7777cd9 100644
--- a/server/tests/drivers/rhevm/common.rb
+++ b/server/tests/drivers/rhevm/common.rb
@@ -1,11 +1,21 @@
+load File.join(File.dirname(__FILE__), '..', '..', 'common.rb')
+
 ENV['API_USER']     = 'vdcadmin@rhev.lab.eng.brq.redhat.com'
 ENV['API_PASSWORD'] = '123456'
 ENV['API_PROVIDER'] = 'https://rhev30-dc.lab.eng.brq.redhat.com:8443/rhevm-api;645e425e-66fe-4ac9-8874-537bd10ef08d'
 
 require 'vcr'
 
+DeltacloudTestCommon::record!
+
 VCR.config do |c|
-  c.cassette_library_dir = "#{File.dirname(__FILE__)}/fixtures/"
+  c.cassette_library_dir = File.join(File.dirname(__FILE__), 'fixtures')
   c.stub_with :webmock
   c.default_cassette_options = { :record => :none }
 end
+
+class WebMock::Config
+  def net_http_connect_on_start
+    true
+  end
+end
diff --git a/server/tests/drivers/rhevm/hardware_profiles_test.rb b/server/tests/drivers/rhevm/hardware_profiles_test.rb
index f701fa9..65b997b 100644
--- a/server/tests/drivers/rhevm/hardware_profiles_test.rb
+++ b/server/tests/drivers/rhevm/hardware_profiles_test.rb
@@ -1,7 +1,6 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rhevm/common'
 
-DeltacloudTestCommon.record!
 module RHEVMTest
 
   class HardwareProfilesTest < Test::Unit::TestCase
diff --git a/server/tests/drivers/rhevm/images_test.rb b/server/tests/drivers/rhevm/images_test.rb
index 3e9948a..61e305b 100644
--- a/server/tests/drivers/rhevm/images_test.rb
+++ b/server/tests/drivers/rhevm/images_test.rb
@@ -1,7 +1,5 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
-DeltacloudTestCommon.record!
+require 'tests/drivers/rhevm/common'
 
 module RHEVMTest
 
diff --git a/server/tests/drivers/rhevm/instances_test.rb b/server/tests/drivers/rhevm/instances_test.rb
index 179eb98..a16ea21 100644
--- a/server/tests/drivers/rhevm/instances_test.rb
+++ b/server/tests/drivers/rhevm/instances_test.rb
@@ -1,7 +1,6 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
+require 'tests/drivers/rhevm/common'
 
-DeltacloudTestCommon.record!
 module RHEVMTest
 
   class InstancesTest < Test::Unit::TestCase
diff --git a/server/tests/drivers/rhevm/realms_test.rb b/server/tests/drivers/rhevm/realms_test.rb
index 2c90578..1fc0667 100644
--- a/server/tests/drivers/rhevm/realms_test.rb
+++ b/server/tests/drivers/rhevm/realms_test.rb
@@ -1,6 +1,6 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-DeltacloudTestCommon.record!
+require 'tests/drivers/rhevm/common'
+
 module RHEVMTest
 
   class RealmsTest < Test::Unit::TestCase
-- 
1.7.10.1


[PATCH core 47/51] RHEVM: Make possible to run RHEV-M tests using Sinatra::Base

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/tests/drivers/rhevm/api_test.rb               |   18 +++++++++++++-----
 server/tests/drivers/rhevm/common.rb                 |   11 +++++++++++
 server/tests/drivers/rhevm/hardware_profiles_test.rb |    8 +++++++-
 server/tests/drivers/rhevm/images_test.rb            |   10 +++++++++-
 server/tests/drivers/rhevm/instances_test.rb         |    8 +++++++-
 server/tests/drivers/rhevm/realms_test.rb            |    9 +++++++--
 server/tests/drivers/rhevm/setup.rb                  |   14 --------------
 7 files changed, 54 insertions(+), 24 deletions(-)
 create mode 100644 server/tests/drivers/rhevm/common.rb
 delete mode 100644 server/tests/drivers/rhevm/setup.rb

diff --git a/server/tests/drivers/rhevm/api_test.rb b/server/tests/drivers/rhevm/api_test.rb
index eea249e..0d8d69e 100644
--- a/server/tests/drivers/rhevm/api_test.rb
+++ b/server/tests/drivers/rhevm/api_test.rb
@@ -7,11 +7,18 @@ module RHEVMTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        use Rack::MatrixParams
+        use Rack::DriverSelect
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_entry_points
-      get_auth_url '/api;driver=rhevm?force_auth=1'
+      get_auth_url '/api;driver=rhevm'
       (last_xml_response/'/api').first[:driver].should == 'rhevm'
       (last_xml_response/'/api/link').length.should > 0
     end
@@ -20,8 +27,8 @@ module RHEVMTest
       get_url '/api;driver=rhevm'
       features = (last_xml_response/'/api/link[@rel="instances"]/feature').collect { |f| f[:name] }
       features.include?('user_name').should == true
-      features.include?('hardware_profiles').should == true
-      features.length.should == 3
+      features.include?('user_data').should == true
+      features.length.should == 2
     end
 
     def test_03_it_has_rhevm_collections
@@ -32,7 +39,8 @@ module RHEVMTest
       collections.include?('images').should == true
       collections.include?('realms').should == true
       collections.include?('hardware_profiles').should == true
-      collections.length.should == 8
+      collections.include?('storage_volumes').should == true
+      collections.length.should == 7
     end
 
   end
diff --git a/server/tests/drivers/rhevm/common.rb b/server/tests/drivers/rhevm/common.rb
new file mode 100644
index 0000000..1ab0f99
--- /dev/null
+++ b/server/tests/drivers/rhevm/common.rb
@@ -0,0 +1,11 @@
+ENV['API_USER']     = 'vdcadmin@rhev.lab.eng.brq.redhat.com'
+ENV['API_PASSWORD'] = '123456'
+ENV['API_PROVIDER'] = 'https://rhev30-dc.lab.eng.brq.redhat.com:8443/rhevm-api;645e425e-66fe-4ac9-8874-537bd10ef08d'
+
+require 'vcr'
+
+VCR.config do |c|
+  c.cassette_library_dir = "#{File.dirname(__FILE__)}/fixtures/"
+  c.stub_with :webmock
+  c.default_cassette_options = { :record => :none }
+end
diff --git a/server/tests/drivers/rhevm/hardware_profiles_test.rb b/server/tests/drivers/rhevm/hardware_profiles_test.rb
index e6323b8..f701fa9 100644
--- a/server/tests/drivers/rhevm/hardware_profiles_test.rb
+++ b/server/tests/drivers/rhevm/hardware_profiles_test.rb
@@ -1,13 +1,19 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
 require 'tests/common'
 
+DeltacloudTestCommon.record!
 module RHEVMTest
 
   class HardwareProfilesTest < Test::Unit::TestCase
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_hardware_profiles
diff --git a/server/tests/drivers/rhevm/images_test.rb b/server/tests/drivers/rhevm/images_test.rb
index 0b8a27b..3e9948a 100644
--- a/server/tests/drivers/rhevm/images_test.rb
+++ b/server/tests/drivers/rhevm/images_test.rb
@@ -1,17 +1,25 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
 require 'tests/common'
 
+DeltacloudTestCommon.record!
+
 module RHEVMTest
 
   class ImagesTest < Test::Unit::TestCase
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_images
       get_auth_url '/api;driver=rhevm/images'
+      puts last_response.body
       (last_xml_response/'images/image').length.should > 0
     end
 
diff --git a/server/tests/drivers/rhevm/instances_test.rb b/server/tests/drivers/rhevm/instances_test.rb
index 1f87a18..179eb98 100644
--- a/server/tests/drivers/rhevm/instances_test.rb
+++ b/server/tests/drivers/rhevm/instances_test.rb
@@ -1,13 +1,19 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
 require 'tests/common'
 
+DeltacloudTestCommon.record!
 module RHEVMTest
 
   class InstancesTest < Test::Unit::TestCase
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_01_it_can_create_instance_without_hardware_profile
diff --git a/server/tests/drivers/rhevm/realms_test.rb b/server/tests/drivers/rhevm/realms_test.rb
index 5f84667..2c90578 100644
--- a/server/tests/drivers/rhevm/realms_test.rb
+++ b/server/tests/drivers/rhevm/realms_test.rb
@@ -1,13 +1,18 @@
 $:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
 require 'tests/common'
-
+DeltacloudTestCommon.record!
 module RHEVMTest
 
   class RealmsTest < Test::Unit::TestCase
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_realms
diff --git a/server/tests/drivers/rhevm/setup.rb b/server/tests/drivers/rhevm/setup.rb
deleted file mode 100644
index 8c58ba2..0000000
--- a/server/tests/drivers/rhevm/setup.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-ENV['API_USER']     = 'vdcadmin@rhev.lab.eng.brq.redhat.com'
-ENV['API_PASSWORD'] = '123456'
-ENV['API_PROVIDER'] = 'https://rhev30-dc.lab.eng.brq.redhat.com:8443/rhevm-api;645e425e-66fe-4ac9-8874-537bd10ef08d'
-
-require 'vcr'
-
-DeltacloudTestCommon::record!
-
-VCR.config do |c|
-  c.cassette_library_dir = "#{File.dirname(__FILE__)}/../../../tests/drivers/rhevm/fixtures/"
-  c.stub_with :webmock
-  c.default_cassette_options = { :record => :none }
-end
-
-- 
1.7.10.1


[PATCH core 27/51] Core: Removed API_ROOT_URL and API_VERSION constants with proper configuration

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/collections/cloud_entry_point.rb   |    2 +-
 server/lib/cimi/helpers.rb                         |    6 +-
 server/lib/cimi/server.rb                          |    2 +-
 server/lib/deltacloud/helpers.rb                   |    4 +-
 server/lib/deltacloud/helpers/deltacloud_helper.rb |    2 +-
 server/lib/deltacloud/helpers/url_helper.rb        |    4 +-
 server/lib/deltacloud_rack.rb                      |   68 ++++++++++++++++++++
 server/tests/drivers/mock/api_test.rb              |   48 +++++++-------
 server/tests/drivers/mock/buckets_test.rb          |    2 +-
 server/tests/drivers/mock/common.rb                |   24 ++-----
 server/tests/drivers/mock/drivers_test.rb          |    2 +-
 .../tests/drivers/mock/hardware_profiles_test.rb   |    2 +-
 server/tests/drivers/mock/images_test.rb           |    2 +-
 server/tests/drivers/mock/instances_test.rb        |    2 +-
 server/tests/drivers/mock/keys_test.rb             |    2 +-
 server/tests/drivers/mock/realms_test.rb           |    2 +-
 .../tests/drivers/mock/storage_snapshots_test.rb   |    2 +-
 server/tests/drivers/mock/storage_volumes_test.rb  |    2 +-
 18 files changed, 118 insertions(+), 60 deletions(-)
 create mode 100644 server/lib/deltacloud_rack.rb

diff --git a/server/lib/cimi/collections/cloud_entry_point.rb b/server/lib/cimi/collections/cloud_entry_point.rb
index 79454f3..8232e61 100644
--- a/server/lib/cimi/collections/cloud_entry_point.rb
+++ b/server/lib/cimi/collections/cloud_entry_point.rb
@@ -23,7 +23,7 @@ module CIMI::Collections
       operation :index do
         description "list all resources of the cloud"
         control do
-          redirect API_ROOT_URL
+          redirect Deltacloud[:root_url]
         end
       end
     end
diff --git a/server/lib/cimi/helpers.rb b/server/lib/cimi/helpers.rb
index 4535c39..b0fc9e3 100644
--- a/server/lib/cimi/helpers.rb
+++ b/server/lib/cimi/helpers.rb
@@ -54,8 +54,8 @@ module CIMI::Collections
     enable :show_errors
     disable :show_exceptions
 
-    set :root_url, API_ROOT_URL
-    set :version, API_VERSION
+    set :root_url, Deltacloud[:root_url]
+    set :version, Deltacloud[:version]
     set :root, File.join(File.dirname(__FILE__), '..', '..')
     set :views, root + '/views/cimi'
     set :public_folder, root + '/public'
@@ -74,7 +74,7 @@ module CIMI::Collections
     end
 
     after do
-      headers 'X-CIMI-Specification-Version' => API_VERSION
+      headers 'X-CIMI-Specification-Version' => Deltacloud[:version]
     end
 
     def self.new_route_for(route, &block)
diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
index a1c7ef9..c34dba9 100644
--- a/server/lib/cimi/server.rb
+++ b/server/lib/cimi/server.rb
@@ -45,7 +45,7 @@ module CIMI
     include CIMI::Collections
     include CIMI::Model
 
-    get API_ROOT_URL do
+    get Deltacloud[:root_url] do
       if params[:force_auth]
         return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
       end
diff --git a/server/lib/deltacloud/helpers.rb b/server/lib/deltacloud/helpers.rb
index 8e265fc..b4f859f 100644
--- a/server/lib/deltacloud/helpers.rb
+++ b/server/lib/deltacloud/helpers.rb
@@ -45,8 +45,8 @@ module Deltacloud::Collections
     enable :method_override
     disable :show_exceptions
 
-    set :root_url, API_ROOT_URL
-    set :version, API_VERSION
+    set :root_url, Deltacloud[:root_url]
+    set :version, Deltacloud[:version]
     set :root, File.join(File.dirname(__FILE__), '..', '..')
     set :views, root + '/views'
     set :public_folder, root + '/public'
diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb b/server/lib/deltacloud/helpers/deltacloud_helper.rb
index 2fc2a59..ed3e57d 100644
--- a/server/lib/deltacloud/helpers/deltacloud_helper.rb
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -20,7 +20,7 @@ module Deltacloud::Helpers
 
     def self.included(klass)
       klass.class_eval do
-        set :root_url, API_ROOT_URL
+        set :root_url, Deltacloud[:root_url]
         include Sinatra::Rabbit
         Sinatra::Rabbit.set :root_path, root_url+'/'
       end
diff --git a/server/lib/deltacloud/helpers/url_helper.rb b/server/lib/deltacloud/helpers/url_helper.rb
index b35c714..fd4d9bc 100644
--- a/server/lib/deltacloud/helpers/url_helper.rb
+++ b/server/lib/deltacloud/helpers/url_helper.rb
@@ -79,7 +79,7 @@ module Sinatra
     def url_for url_fragment, mode=:path_only
       case mode
       when :path_only
-        base = request.script_name.empty? ? API_ROOT_URL : request.script_name
+        base = request.script_name.empty? ? Deltacloud[:root_url] : request.script_name
       when :full
         scheme = request.scheme
         port = request.port
@@ -96,7 +96,7 @@ module Sinatra
         else
           port = ":#{port}"
         end
-        base = "#{scheme}://#{request_host}#{port}#{request.script_name.empty? ? API_ROOT_URL : request.script_name}"
+        base = "#{scheme}://#{request_host}#{port}#{request.script_name.empty? ? Deltacloud[:root_url] : request.script_name}"
       else
         raise TypeError, "Unknown url_for mode #{mode}"
       end
diff --git a/server/lib/deltacloud_rack.rb b/server/lib/deltacloud_rack.rb
new file mode 100644
index 0000000..873ef29
--- /dev/null
+++ b/server/lib/deltacloud_rack.rb
@@ -0,0 +1,68 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+
+  def self.config(conf=nil)
+    @config ||= conf
+  end
+
+  def self.configure(&block)
+    config(Server.new(&block))
+    self
+  end
+
+  def self.[](item)
+    config.send(item)
+  end
+
+  def self.require_frontend!
+    ENV['API_FRONTEND'] ||= 'deltacloud'
+    require File.join(File.dirname(__FILE__), ENV['API_FRONTEND'], 'server.rb')
+    config.klass eval(self[:klass])
+  end
+
+  class Server
+
+    attr_reader :root_url
+    attr_reader :version
+    attr_reader :klass
+
+    def initialize(opts={}, &block)
+      @root_url = opts[:root_url]
+      @version = opts[:version]
+      @klass = opts[:klass]
+      instance_eval(&block)
+    end
+
+    def root_url(url=nil)
+      return @root_url if url.nil?
+      raise '[Core] The server URL must start with /' unless url =~ /^\//
+      @root_url = url
+    end
+
+    def version(version=nil)
+      return @version if version.nil?
+      @version = version
+    end
+
+    def klass(k=nil)
+      return @klass if k.nil?
+      @klass = k
+    end
+
+  end
+
+end
diff --git a/server/tests/drivers/mock/api_test.rb b/server/tests/drivers/mock/api_test.rb
index 3308365..cafe0be 100644
--- a/server/tests/drivers/mock/api_test.rb
+++ b/server/tests/drivers/mock/api_test.rb
@@ -2,37 +2,37 @@ describe 'Deltacloud API' do
   include Deltacloud::Test
 
   it 'return HTTP_OK when accessing API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     last_response.status.must_equal 200
   end
 
   it 'advertise the current driver in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     xml_response.root[:driver].must_equal ENV['API_DRIVER']
   end
 
   it 'advertise the current API version in API entrypoint' do
-    get API_ROOT_URL
-    xml_response.root[:version].must_equal API_VERSION
+    get Deltacloud[:root_url]
+    xml_response.root[:version].must_equal Deltacloud[:version]
   end
 
   it 'advertise the current API version in HTTP headers' do
-    get API_ROOT_URL
-    last_response.headers['Server'].must_equal "Apache-Deltacloud/#{API_VERSION}"
+    get Deltacloud[:root_url]
+    last_response.headers['Server'].must_equal "Apache-Deltacloud/#{Deltacloud[:version]}"
   end
 
   it 'must include the ETag in HTTP headers' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     last_response.headers['ETag'].wont_be_nil
   end
 
   it 'advertise collections in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link').wont_be_empty
   end
 
   it 'include the :href and :rel attribute for each collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link').each do |collection|
       collection[:href].wont_be_nil
       collection[:rel].wont_be_nil
@@ -40,19 +40,19 @@ describe 'Deltacloud API' do
   end
 
   it 'uses the absolute URI in the :href attribute for each collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link').each do |collection|
       collection[:href].must_match /^http/
     end
   end
 
   it 'advertise features for some collections in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link/feature').wont_be_empty
   end
 
   it 'advertise the name of the feature for some collections in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link/feature').each do |f|
       f[:name].wont_be_nil
     end
@@ -60,55 +60,55 @@ describe 'Deltacloud API' do
 
   it 'must change the media type from XML to JSON using Accept headers' do
     header 'Accept', 'application/json'
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     last_response.headers['Content-Type'].must_equal 'application/json'
   end
 
   it 'must change the media type to JSON using the "?format" parameter in URL' do
-    get API_ROOT_URL, { :format => 'json' }
+    get Deltacloud[:root_url], { :format => 'json' }
     last_response.headers['Content-Type'].must_equal 'application/json'
   end
 
   it 'must change the driver when using X-Deltacloud-Driver HTTP header' do
     header 'X-Deltacloud-Driver', 'ec2'
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     xml_response.root[:driver].must_equal 'ec2'
     header 'X-Deltacloud-Driver', 'mock'
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     xml_response.root[:driver].must_equal 'mock'
   end
 
   it 'must change the features when driver is swapped using HTTP headers' do
     header 'X-Deltacloud-Driver', 'ec2'
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     # The 'user_name' feature is not supported currently for the EC2 driver
     (xml_response/'api/link/feature').map { |f| f[:name] }.wont_include 'user_name'
     header 'X-Deltacloud-Driver', 'mock'
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     # But it's supported in Mock driver
     (xml_response/'api/link/feature').map { |f| f[:name] }.must_include 'user_name'
   end
 
   it 'must re-validate the driver credentials when using "?force_auth" parameter in URL' do
-    get API_ROOT_URL, { :force_auth => '1' }
+    get Deltacloud[:root_url], { :force_auth => '1' }
     last_response.status.must_equal 401
     auth_as_mock
-    get API_ROOT_URL, { :force_auth => '1' }
+    get Deltacloud[:root_url], { :force_auth => '1' }
     last_response.status.must_equal 200
   end
 
   it 'must change the API PROVIDER using the /api;provider matrix parameter in URI' do
-    get API_ROOT_URL + ';provider=test1'
+    get Deltacloud[:root_url] + ';provider=test1'
     xml_response.root[:provider].wont_be_nil
     xml_response.root[:provider].must_equal 'test1'
-    get API_ROOT_URL + ';provider=test2'
+    get Deltacloud[:root_url] + ';provider=test2'
     xml_response.root[:provider].must_equal 'test2'
   end
 
   it 'must change the API DRIVER using the /api;driver matrix parameter in URI' do
-    get API_ROOT_URL + ';driver=ec2'
+    get Deltacloud[:root_url] + ';driver=ec2'
     xml_response.root[:driver].must_equal 'ec2'
-    get API_ROOT_URL + ';driver=mock'
+    get Deltacloud[:root_url] + ';driver=mock'
     xml_response.root[:driver].must_equal 'mock'
   end
 
diff --git a/server/tests/drivers/mock/buckets_test.rb b/server/tests/drivers/mock/buckets_test.rb
index f98ad24..91970ff 100644
--- a/server/tests/drivers/mock/buckets_test.rb
+++ b/server/tests/drivers/mock/buckets_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API buckets' do
   include Deltacloud::Test
 
   it 'must advertise have the buckets collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=buckets]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/common.rb b/server/tests/drivers/mock/common.rb
index 08650a3..2b96711 100644
--- a/server/tests/drivers/mock/common.rb
+++ b/server/tests/drivers/mock/common.rb
@@ -1,25 +1,15 @@
-unless Kernel.respond_to?(:require_relative)
-  module Kernel
-    def require_relative(path)
-      require File.join(File.dirname(caller[0]), path.to_str)
-    end
-  end
-end
+load File.join(File.dirname(__FILE__), '..', '..', '..', 'lib', 'deltacloud_rack.rb')
 
-API_ROOT_URL = "/api" unless defined?(API_ROOT_URL)
-API_VERSION = "1.0.0" unless defined?(API_VERSION)
-ENV['API_DRIVER'] ||= 'mock'
-
-ENV['API_USERNAME'] ||= 'mockuser'
-ENV['API_PASSWORD'] ||= 'mockpassword'
-
-require_relative '../../../lib/deltacloud/server.rb'
+Deltacloud::configure do |server|
+  server.root_url '/api'
+  server.version '0.5.0'
+  server.klass 'Deltacloud::API'
+end.require_frontend!
 
 require 'minitest/autorun'
 require 'rack/test'
 require 'nokogiri'
 require 'json'
-
 require 'pp'
 
 module Deltacloud
@@ -43,7 +33,7 @@ module Deltacloud
     end
 
     def collection_url(collection)
-      [API_ROOT_URL, collection.to_s].join('/')
+      [Deltacloud[:root_url], collection.to_s].join('/')
     end
 
     def app
diff --git a/server/tests/drivers/mock/drivers_test.rb b/server/tests/drivers/mock/drivers_test.rb
index 41c2e66..9e5bc71 100644
--- a/server/tests/drivers/mock/drivers_test.rb
+++ b/server/tests/drivers/mock/drivers_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API drivers' do
   include Deltacloud::Test
 
   it 'must advertise have the drivers collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=drivers]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/hardware_profiles_test.rb b/server/tests/drivers/mock/hardware_profiles_test.rb
index 3dad5a8..aed2a04 100644
--- a/server/tests/drivers/mock/hardware_profiles_test.rb
+++ b/server/tests/drivers/mock/hardware_profiles_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API Hardware Profiles' do
   include Deltacloud::Test
 
   it 'must advertise have the hardware_profiles collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=hardware_profiles]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/images_test.rb b/server/tests/drivers/mock/images_test.rb
index 3faf752..909fdf1 100644
--- a/server/tests/drivers/mock/images_test.rb
+++ b/server/tests/drivers/mock/images_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API Images' do
   include Deltacloud::Test
 
   it 'must advertise have the images collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=images]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/instances_test.rb b/server/tests/drivers/mock/instances_test.rb
index c601a6f..878589c 100644
--- a/server/tests/drivers/mock/instances_test.rb
+++ b/server/tests/drivers/mock/instances_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API instances' do
   include Deltacloud::Test
 
   it 'must advertise have the instances collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=instances]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/keys_test.rb b/server/tests/drivers/mock/keys_test.rb
index 9267b5a..2738a50 100644
--- a/server/tests/drivers/mock/keys_test.rb
+++ b/server/tests/drivers/mock/keys_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API Keys' do
   include Deltacloud::Test
 
   it 'must advertise have the keys collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=keys]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/realms_test.rb b/server/tests/drivers/mock/realms_test.rb
index 6bc9101..5496bc4 100644
--- a/server/tests/drivers/mock/realms_test.rb
+++ b/server/tests/drivers/mock/realms_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API Realms' do
   include Deltacloud::Test
 
   it 'must advertise have the realms collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=realms]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/storage_snapshots_test.rb b/server/tests/drivers/mock/storage_snapshots_test.rb
index 52ea847..70ac2ba 100644
--- a/server/tests/drivers/mock/storage_snapshots_test.rb
+++ b/server/tests/drivers/mock/storage_snapshots_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API storage_snapshots' do
   include Deltacloud::Test
 
   it 'must advertise have the storage_snapshots collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=storage_snapshots]').wont_be_empty
   end
 
diff --git a/server/tests/drivers/mock/storage_volumes_test.rb b/server/tests/drivers/mock/storage_volumes_test.rb
index cbafd5d..efceaee 100644
--- a/server/tests/drivers/mock/storage_volumes_test.rb
+++ b/server/tests/drivers/mock/storage_volumes_test.rb
@@ -2,7 +2,7 @@ describe 'Deltacloud API storage_volumes' do
   include Deltacloud::Test
 
   it 'must advertise have the storage_volumes collection in API entrypoint' do
-    get API_ROOT_URL
+    get Deltacloud[:root_url]
     (xml_response/'api/link[@rel=storage_volumes]').wont_be_empty
   end
 
-- 
1.7.10.1


RE: [PATCH core 32/51] FGCP: Renamed :default to 'default' and updated comment which points to entrypoints

Posted by "Koper, Dies" <di...@fast.au.fujitsu.com>.
ACK to the combination of this patch with 26/51 and 31/51.
Tested and worked fine with FGCP.

Regards,
Dies Koper

> -----Original Message-----
> From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> Sent: Monday, 21 May 2012 8:07 PM
> To: dev@deltacloud.apache.org
> Subject: [PATCH core 32/51] FGCP: Renamed :default to 'default' and
> updated comment which points to entrypoints
> 
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    2 +-
>  server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> index c544998..9072c84 100644
> --- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> @@ -35,7 +35,7 @@ class FGCPClient
>      @locale = locale
>      cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
>      country = $1.downcase
> -    endpoint =
>
Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][:default][countr
y]
> unless endpoint
> +    endpoint =
>
Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'][count
ry]
> unless endpoint
>      raise "API endpoint not found for region #{country}" if
endpoint.nil?
> 
>      #proxy settings:
> diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> index 0729ae4..93ab8fa 100644
> --- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> @@ -1136,7 +1136,7 @@ eofwopxml
>      cert, key = convert_credentials(credentials)
>      cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
>      country = $1.downcase
> -    endpoint =
>
Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][:default][countr
y]
> +    endpoint =
>
Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'][count
ry]
>      [
>        Provider.new(
>          :id => "fgcp-#{country}",
> @@ -1148,7 +1148,7 @@ eofwopxml
> 
>  # following code enables region drop-down box on GUI. No need as
> retrieving region from cert (subject c)
>  #  def configured_providers
> -#    Deltacloud::Drivers::driver_config[:fgcp][:entrypoints].keys
> +#
Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'].keys
>  #  end
> 
>    exceptions do
> --
> 1.7.10.1
> 



[PATCH core 32/51] FGCP: Renamed :default to 'default' and updated comment which points to entrypoints

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    2 +-
 server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
index c544998..9072c84 100644
--- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
+++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
@@ -35,7 +35,7 @@ class FGCPClient
     @locale = locale
     cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
     country = $1.downcase
-    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][:default][country] unless endpoint
+    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'][country] unless endpoint
     raise "API endpoint not found for region #{country}" if endpoint.nil?
 
     #proxy settings:
diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
index 0729ae4..93ab8fa 100644
--- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
+++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
@@ -1136,7 +1136,7 @@ eofwopxml
     cert, key = convert_credentials(credentials)
     cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
     country = $1.downcase
-    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][:default][country]
+    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'][country]
     [
       Provider.new(
         :id => "fgcp-#{country}",
@@ -1148,7 +1148,7 @@ eofwopxml
 
 # following code enables region drop-down box on GUI. No need as retrieving region from cert (subject c)
 #  def configured_providers
-#    Deltacloud::Drivers::driver_config[:fgcp][:entrypoints].keys
+#    Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'].keys
 #  end
 
   exceptions do
-- 
1.7.10.1


[PATCH core 43/51] Core: Added capability check if the driver support the state machine

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 .../lib/deltacloud/collections/instance_states.rb  |    4 ++-
 server/tests/drivers/google/setup.rb               |   38 --------------------
 server/views/instance_states/show.html.haml        |    2 +-
 3 files changed, 4 insertions(+), 40 deletions(-)
 delete mode 100644 server/tests/drivers/google/setup.rb

diff --git a/server/lib/deltacloud/collections/instance_states.rb b/server/lib/deltacloud/collections/instance_states.rb
index 56c1561..6122cca 100644
--- a/server/lib/deltacloud/collections/instance_states.rb
+++ b/server/lib/deltacloud/collections/instance_states.rb
@@ -16,8 +16,10 @@
 module Deltacloud::Collections
   class InstanceStates < Base
 
+    check_capability :for => lambda { |m| !driver.send(m).nil? }
+
     collection :instance_states do
-      operation :index do
+      operation :index, :with_capability => :instance_state_machine do
         control do
           @machine = driver.instance_state_machine
           respond_to do |format|
diff --git a/server/tests/drivers/google/setup.rb b/server/tests/drivers/google/setup.rb
deleted file mode 100644
index 95924e5..0000000
--- a/server/tests/drivers/google/setup.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-ENV['API_DRIVER']   = "google"
-ENV['API_USER']     = 'GOOGK7JXLS6UEYS6AYVO'
-ENV['API_PASSWORD'] = 'QjxUunLgszKhBGn/LISQajGR82CfwvraxA9lqnkg'
-
-require 'vcr'
-
-DeltacloudTestCommon::record!
-
-VCR.config do |c|
-  c.cassette_library_dir = "#{File.dirname(__FILE__)}/fixtures/"
-  c.stub_with :excon
-  c.default_cassette_options = { :record => :new_episodes}
-end
-
-#monkey patch fix for VCR normalisation code:
-#see https://github.com/myronmarston/vcr/issues/4
-#when body is a tempfile, like when creating new blob
-#this method of normalisation fails and excon throws errors
-#(Excon::Errors::SocketError:can't convert Tempfile into String)
-#
-#RELEVANT: https://github.com/myronmarston/vcr/issues/101
-#(will need revisiting when vcr 2 comes along)
-
-module VCR
-  module Normalizers
-    module Body
-
-    private
-    def normalize_body
-     self.body = case body
-          when nil, ''; nil
-          else
-            String.new(body) unless body.is_a?(Tempfile)
-        end
-      end
-    end
-  end
-end
diff --git a/server/views/instance_states/show.html.haml b/server/views/instance_states/show.html.haml
index c81a3c3..252f249 100644
--- a/server/views/instance_states/show.html.haml
+++ b/server/views/instance_states/show.html.haml
@@ -2,7 +2,7 @@
 =subheader "#{driver_symbol}@#{Thread::current[:provider] || ENV['API_PROVIDER'] || 'default'}"
 
 %div{ :'data-role' => :content, :'data-theme' => 'd', :class => 'middle-dialog'}
-  = image_tag api_url_for('instance_states?format=png')
+  %img{ :src => api_url_for('instance_states?format=png') }
 
   %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-theme' => 'a'}
     - @machine.states.each do |state|
-- 
1.7.10.1


[PATCH core 30/51] Test: Make possible to run the Openstack unit test

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/tests/common.rb                                  |   15 +++++++--------
 server/tests/drivers/openstack/api_test.rb              |    7 ++++++-
 .../tests/drivers/openstack/hardware_profiles_test.rb   |    7 ++++++-
 server/tests/drivers/openstack/images_test.rb           |    7 ++++++-
 server/tests/drivers/openstack/instances_test.rb        |    7 ++++++-
 server/tests/drivers/openstack/realms_test.rb           |    7 ++++++-
 6 files changed, 37 insertions(+), 13 deletions(-)
 create mode 100644 server/tests/drivers/openstack/common.rb

diff --git a/server/tests/common.rb b/server/tests/common.rb
index 528f86d..9d557cf 100644
--- a/server/tests/common.rb
+++ b/server/tests/common.rb
@@ -28,9 +28,14 @@ require 'json'
 require 'digest/sha1'
 require 'base64'
 require 'rack/test'
-require "%s/server" % (ENV['API_FRONTEND'] == 'cimi' ? 'cimi' : 'deltacloud')
 
-driver
+load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud_rack.rb')
+
+Deltacloud::configure do |server|
+  server.root_url '/api'
+  server.version '0.5.0'
+  server.klass 'Deltacloud::API'
+end.require_frontend!
 
 # Set proper environment variables for running test
 
@@ -38,12 +43,6 @@ ENV['RACK_ENV']     = 'test'
 ENV['API_HOST']     = 'localhost'
 ENV['API_PORT']     = '4040'
 
-configure :test do
-  set :environment, :test
-  set :raise_errors, false
-  set :show_exceptions, false
-end
-
 RSpec.configure do |conf|
   conf.include Rack::Test::Methods
   conf.expect_with :rspec
diff --git a/server/tests/drivers/openstack/api_test.rb b/server/tests/drivers/openstack/api_test.rb
index 14861b0..b9c3fb2 100644
--- a/server/tests/drivers/openstack/api_test.rb
+++ b/server/tests/drivers/openstack/api_test.rb
@@ -7,7 +7,12 @@ module OpenstackTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_entry_points
diff --git a/server/tests/drivers/openstack/common.rb b/server/tests/drivers/openstack/common.rb
new file mode 100644
index 0000000..e69de29
diff --git a/server/tests/drivers/openstack/hardware_profiles_test.rb b/server/tests/drivers/openstack/hardware_profiles_test.rb
index 0744011..68a4f0c 100644
--- a/server/tests/drivers/openstack/hardware_profiles_test.rb
+++ b/server/tests/drivers/openstack/hardware_profiles_test.rb
@@ -7,7 +7,12 @@ module OpenstackTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_hardware_profiles
diff --git a/server/tests/drivers/openstack/images_test.rb b/server/tests/drivers/openstack/images_test.rb
index 9b71653..3049364 100644
--- a/server/tests/drivers/openstack/images_test.rb
+++ b/server/tests/drivers/openstack/images_test.rb
@@ -7,7 +7,12 @@ module OpenstackTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_images
diff --git a/server/tests/drivers/openstack/instances_test.rb b/server/tests/drivers/openstack/instances_test.rb
index c2e2b76..d7da173 100644
--- a/server/tests/drivers/openstack/instances_test.rb
+++ b/server/tests/drivers/openstack/instances_test.rb
@@ -7,7 +7,12 @@ module OpenstackTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_01_it_can_create_instance_without_hardware_profile
diff --git a/server/tests/drivers/openstack/realms_test.rb b/server/tests/drivers/openstack/realms_test.rb
index f62a6f9..613e5ec 100644
--- a/server/tests/drivers/openstack/realms_test.rb
+++ b/server/tests/drivers/openstack/realms_test.rb
@@ -7,7 +7,12 @@ module OpenstackTest
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_realms
-- 
1.7.10.1


RE: [PATCH core 34/51] Client: Fixed client rspec tests to work against modular version

Posted by "Koper, Dies" <di...@fast.au.fujitsu.com>.
> +        puts blob.inspect

Is this intentional?

Regards,
Dies Koper


> -----Original Message-----
> From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> Sent: Monday, 21 May 2012 8:07 PM
> To: dev@deltacloud.apache.org
> Subject: [PATCH core 34/51] Client: Fixed client rspec tests to work
against
> modular version
> 
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  client/specs/buckets_spec.rb     |    1 +
>  client/specs/content_spec.rb     |    4 ++--
>  server/views/blobs/show.xml.haml |    2 +-
>  3 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/client/specs/buckets_spec.rb
b/client/specs/buckets_spec.rb
> index 81b1e58..b897e0c 100644
> --- a/client/specs/buckets_spec.rb
> +++ b/client/specs/buckets_spec.rb
> @@ -96,6 +96,7 @@ describe "Blobs" do
>        blob_list.size.should eql(bucket.size.to_i)
>        blob_list.each do |b_id|
>          blob = client.blob({"bucket" => bucket.name, :id => b_id})
> +        puts blob.inspect
>          blob.bucket.should_not be_nil
>          blob.bucket.should be_a(String)
>          blob.bucket.should eql(bucket.name)
> diff --git a/client/specs/content_spec.rb
b/client/specs/content_spec.rb
> index c953660..ffd222c 100644
> --- a/client/specs/content_spec.rb
> +++ b/client/specs/content_spec.rb
> @@ -58,7 +58,7 @@ end
>  describe "return HTML in different browsers" do
> 
>    it "wants XML using format parameter" do
> -    client['?format=xml'].get('Accept' => 'application/xhtml+xml') do
> |response, request, &block|
> +    client.get(:params => { 'format' => 'xml' }, 'Accept' =>
> 'application/xhtml+xml') do |response, request, &block|
>        response.code.should == 200
>        response.headers[:content_type].should =~ /^application\/xml/
>      end
> @@ -71,7 +71,7 @@ describe "return HTML in different browsers" do
>    end
> 
>    it "wants HTML using format parameter and accept set to XML" do
> -    client['?format=html'].get('Accept' => 'application/xml') do
|response,
> request, &block|
> +    client.get(:params => { 'format' => 'html'}, 'Accept' =>
'application/xml')
> do |response, request, &block|
>        response.code.should == 200
>        response.headers[:content_type].should =~ /^text\/html/
>      end
> diff --git a/server/views/blobs/show.xml.haml
> b/server/views/blobs/show.xml.haml
> index bde9e80..ba3d4de 100644
> --- a/server/views/blobs/show.xml.haml
> +++ b/server/views/blobs/show.xml.haml
> @@ -1,6 +1,6 @@
>  !!! XML
>  %blob{:href => bucket_url(@blob.bucket) + '/' + @blob.id, :id =>
@blob.id}
> -  %bucket{ :id => @blob.bucket, :href => bucket_url(@blob.bucket)}
> +  %bucket{ :id => @blob.bucket, :href => bucket_url(@blob.bucket),
:rel
> => :bucket}
>    - @blob.attributes.select{ |attr| (attr!=:id &&
> attr!=:user_metadata) }.each do |attribute|
>      - next if attribute == :bucket
>      - unless attribute == :content
> --
> 1.7.10.1
> 



[PATCH core 34/51] Client: Fixed client rspec tests to work against modular version

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 client/specs/buckets_spec.rb     |    1 +
 client/specs/content_spec.rb     |    4 ++--
 server/views/blobs/show.xml.haml |    2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/client/specs/buckets_spec.rb b/client/specs/buckets_spec.rb
index 81b1e58..b897e0c 100644
--- a/client/specs/buckets_spec.rb
+++ b/client/specs/buckets_spec.rb
@@ -96,6 +96,7 @@ describe "Blobs" do
       blob_list.size.should eql(bucket.size.to_i)
       blob_list.each do |b_id|
         blob = client.blob({"bucket" => bucket.name, :id => b_id})
+        puts blob.inspect
         blob.bucket.should_not be_nil
         blob.bucket.should be_a(String)
         blob.bucket.should eql(bucket.name)
diff --git a/client/specs/content_spec.rb b/client/specs/content_spec.rb
index c953660..ffd222c 100644
--- a/client/specs/content_spec.rb
+++ b/client/specs/content_spec.rb
@@ -58,7 +58,7 @@ end
 describe "return HTML in different browsers" do
 
   it "wants XML using format parameter" do
-    client['?format=xml'].get('Accept' => 'application/xhtml+xml') do |response, request, &block|
+    client.get(:params => { 'format' => 'xml' }, 'Accept' => 'application/xhtml+xml') do |response, request, &block|
       response.code.should == 200
       response.headers[:content_type].should =~ /^application\/xml/
     end
@@ -71,7 +71,7 @@ describe "return HTML in different browsers" do
   end
 
   it "wants HTML using format parameter and accept set to XML" do
-    client['?format=html'].get('Accept' => 'application/xml') do |response, request, &block|
+    client.get(:params => { 'format' => 'html'}, 'Accept' => 'application/xml') do |response, request, &block|
       response.code.should == 200
       response.headers[:content_type].should =~ /^text\/html/
     end
diff --git a/server/views/blobs/show.xml.haml b/server/views/blobs/show.xml.haml
index bde9e80..ba3d4de 100644
--- a/server/views/blobs/show.xml.haml
+++ b/server/views/blobs/show.xml.haml
@@ -1,6 +1,6 @@
 !!! XML
 %blob{:href => bucket_url(@blob.bucket) + '/' + @blob.id, :id => @blob.id}
-  %bucket{ :id => @blob.bucket, :href => bucket_url(@blob.bucket)}
+  %bucket{ :id => @blob.bucket, :href => bucket_url(@blob.bucket), :rel => :bucket}
   - @blob.attributes.select{ |attr| (attr!=:id && attr!=:user_metadata) }.each do |attribute|
     - next if attribute == :bucket
     - unless attribute == :content
-- 
1.7.10.1


[PATCH core 07/51] Core: Added check if user_metadata in blob respond to the :each method

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/views/blobs/show.xml.haml |   11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/server/views/blobs/show.xml.haml b/server/views/blobs/show.xml.haml
index 34b9cca..bde9e80 100644
--- a/server/views/blobs/show.xml.haml
+++ b/server/views/blobs/show.xml.haml
@@ -1,11 +1,14 @@
 !!! XML
 %blob{:href => bucket_url(@blob.bucket) + '/' + @blob.id, :id => @blob.id}
+  %bucket{ :id => @blob.bucket, :href => bucket_url(@blob.bucket)}
   - @blob.attributes.select{ |attr| (attr!=:id && attr!=:user_metadata) }.each do |attribute|
+    - next if attribute == :bucket
     - unless attribute == :content
       - haml_tag(attribute, :<) do
         - haml_concat @blob.send(attribute)
   %user_metadata
-    - @blob.user_metadata.each do |k, v|
-      %entry{:key => k}
-        #{cdata v}
-  %content{:href => bucket_url(@blob.bucket) + '/' + @blob.id + '/content'}
+    - if @blob.user_metadata.respond_to? :each
+      - @blob.user_metadata.each do |k, v|
+        %entry{:key => k}
+          #{cdata v}
+  %content{:href => bucket_url(@blob.bucket) + '/' + @blob.id + '/content', :rel => 'blob_content'}
-- 
1.7.10.1


[PATCH core 41/51] Add a core_ext.rb to ease loading of all core extensions

Posted by mf...@redhat.com.
From: David Lutterkort <lu...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud.rb          |    6 +-----
 server/lib/deltacloud/core_ext.rb |   21 +++++++++++++++++++++
 server/lib/deltacloud_rack.rb     |    6 +-----
 server/spec/spec_helper.rb        |    4 +---
 4 files changed, 24 insertions(+), 13 deletions(-)
 create mode 100644 server/lib/deltacloud/core_ext.rb

diff --git a/server/lib/deltacloud.rb b/server/lib/deltacloud.rb
index 6160cce..bf5345f 100644
--- a/server/lib/deltacloud.rb
+++ b/server/lib/deltacloud.rb
@@ -18,11 +18,7 @@ require 'ostruct'
 
 load File.join(File.dirname(__FILE__), 'deltacloud/core_ext.rb')
 
-require_relative 'deltacloud/core_ext/string'
-require_relative 'deltacloud/core_ext/array'
-require_relative 'deltacloud/core_ext/hash'
-require_relative 'deltacloud/core_ext/integer'
-require_relative 'deltacloud/core_ext/proc'
+require_relative 'deltacloud/core_ext'
 require_relative 'deltacloud/models'
 require_relative 'deltacloud/drivers'
 require_relative 'deltacloud/helpers/driver_helper'
diff --git a/server/lib/deltacloud/core_ext.rb b/server/lib/deltacloud/core_ext.rb
new file mode 100644
index 0000000..b54df66
--- /dev/null
+++ b/server/lib/deltacloud/core_ext.rb
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+require 'deltacloud/core_ext/array'
+require 'deltacloud/core_ext/hash'
+require 'deltacloud/core_ext/integer'
+require 'deltacloud/core_ext/proc'
+require 'deltacloud/core_ext/string'
diff --git a/server/lib/deltacloud_rack.rb b/server/lib/deltacloud_rack.rb
index a52354c..e59b11a 100644
--- a/server/lib/deltacloud_rack.rb
+++ b/server/lib/deltacloud_rack.rb
@@ -21,11 +21,7 @@ unless Kernel.respond_to?(:require_relative)
   end
 end
 
-require_relative './deltacloud/core_ext/string'
-require_relative './deltacloud/core_ext/array'
-require_relative './deltacloud/core_ext/hash'
-require_relative './deltacloud/core_ext/integer'
-require_relative './deltacloud/core_ext/proc'
+require_relative './deltacloud/core_ext'
 
 module Deltacloud
 
diff --git a/server/spec/spec_helper.rb b/server/spec/spec_helper.rb
index 22809e2..51aa1fe 100644
--- a/server/spec/spec_helper.rb
+++ b/server/spec/spec_helper.rb
@@ -19,9 +19,7 @@ require 'pp'
 require 'rspec/core'
 require 'xmlsimple'
 
-load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud', 'core_ext', 'array.rb')
-load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud', 'core_ext', 'string.rb')
-load File.join(File.dirname(__FILE__), '..', 'lib', 'cimi', 'models.rb')
+load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud', 'core_ext.rb')
 
 DATA_DIR = File::join(File::expand_path(File::dirname(__FILE__)), 'cimi', 'data')
 
-- 
1.7.10.1


Re: Deltacloud revamp using Sinatra::Base (rev 3 - final? ;-)

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/21/12, mfojtik@redhat.com wrote:

Also sorry for the 51 patches flood, I tried **very** hard to squash them ;-) 

> Hi,
> 
> Sorry for the 'super-big-patch' once again, but this should be the final stable
> version with all nits and tests fixed so far.
> 
> The test that does not work include RHEV-M (vcr fixtures need to refresh).
> Revision 3 also include a basic test suite for the new library code to assure
> the drivers API is stable and various feature-related fixes, including the
> constraints settings.
> 
> The final code should run fine under Ruby 1.9 and also on Ruby 1.8.
> I don't have any github repo right now, because maintaing those turns to be a
> nightmare, since I need to rebase after every push.
> 
>   -- Michal
> 

-- 
Michal Fojtik
Sr. Software Engineer, Deltacloud API (http://deltacloud.org)

[PATCH core 42/51] * spec/spec_helper.rb: define require_relative

Posted by mf...@redhat.com.
From: David Lutterkort <lu...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/spec/spec_helper.rb |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/server/spec/spec_helper.rb b/server/spec/spec_helper.rb
index 51aa1fe..47b8672 100644
--- a/server/spec/spec_helper.rb
+++ b/server/spec/spec_helper.rb
@@ -19,7 +19,16 @@ require 'pp'
 require 'rspec/core'
 require 'xmlsimple'
 
-load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud', 'core_ext.rb')
+unless Kernel.respond_to?(:require_relative)
+  module Kernel
+    def require_relative(path)
+      require File.join(File.dirname(caller[0]), path.to_str)
+    end
+  end
+end
+
+require_relative '../lib/deltacloud/core_ext.rb'
+require_relative '../lib/cimi/models.rb'
 
 DATA_DIR = File::join(File::expand_path(File::dirname(__FILE__)), 'cimi', 'data')
 
-- 
1.7.10.1


RE: [PATCH core 49/51] FGCP: Renamed the driver class to be loadable and removed DEFAULT_CONFIG constant, because it's not longer set

Posted by "Koper, Dies" <di...@fast.au.fujitsu.com>.
Hi Michal,

We found another issue:

NameError:uninitialized constant
Deltacloud::Drivers::Fgcp::FgcpDriver::FGCPClient
./lib/deltacloud/./helpers/../drivers/fgcp/fgcp_driver.rb:1205:in
`new_client'
./lib/deltacloud/./helpers/../drivers/fgcp/fgcp_driver.rb:103:in
`images'

This error is caused by an inconsistence module name in fgcp_client.rb
--------------------------------
module Deltacloud
  module Drivers
    module FGCP  <=== This should be changed to Fgcp

class FGCPClient <=== and probably better to change this to FgcpClient
to be consistent? (Also in driver's new_client method) 
... ...
--------------------------------

Regards,
Dies Koper


> -----Original Message-----
> From: Michal Fojtik [mailto:mfojtik@redhat.com]
> Sent: Monday, 21 May 2012 10:45 PM
> To: dev@deltacloud.apache.org
> Subject: Re: [PATCH core 49/51] FGCP: Renamed the driver class to be
> loadable and removed DEFAULT_CONFIG constant, because it's not longer
> set
> 
> On 05/21/12, Koper, Dies wrote:
> > Hi Michal,
> >
> > > -  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> > > File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
> > > +  CERT_DIR = ENV['FGCP_CERT_DIR']
> >
> > I thought that we agreed on IRC to use something like
> > +  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> > File::expand_path('~\.deltacloud\config\fgcp')
> > ?
> 
> Right. I'll add that before push, thanks for reminding me.
> 
>   -- Michal
> 
> >
> > Regards,
> > Dies Koper
> >
> >
> >
> > > -----Original Message-----
> > > From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> > > Sent: Monday, 21 May 2012 8:08 PM
> > > To: dev@deltacloud.apache.org
> > > Subject: [PATCH core 49/51] FGCP: Renamed the driver class to be
> > loadable
> > > and removed DEFAULT_CONFIG constant, because it's not longer set
> > >
> > > From: Michal Fojtik <mf...@redhat.com>
> > >
> > >
> > > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > > ---
> > >  server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    1 -
> > >  server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    9
++++-----
> > >  2 files changed, 4 insertions(+), 6 deletions(-)
> > >
> > > diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > > b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > > index 9072c84..b0e1897 100644
> > > --- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > > +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > > @@ -15,7 +15,6 @@
> > >  #
> > >  # Author: Dies Koper <di...@fast.au.fujitsu.com>
> > >
> > > -require 'deltacloud/base_driver'
> > >  require 'net/http'
> > >  require 'net/https'
> > >  require 'rubygems'
> > > diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > > b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > > index 93ab8fa..4d65e7c 100644
> > > --- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > > +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > > @@ -15,17 +15,16 @@
> > >  #
> > >  # Author: Dies Koper <di...@fast.au.fujitsu.com>
> > >
> > > -require 'deltacloud/base_driver'
> > > -require 'deltacloud/drivers/fgcp/fgcp_client'
> > > +require_relative 'fgcp_client'
> > >  require 'openssl'
> > >  require 'xmlsimple'
> > >
> > >  module Deltacloud
> > >    module Drivers
> > > -    module FGCP
> > > -class FGCPDriver < Deltacloud::BaseDriver
> > > +    module Fgcp
> > > +class FgcpDriver < Deltacloud::BaseDriver
> > >
> > > -  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> > > File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
> > > +  CERT_DIR = ENV['FGCP_CERT_DIR']
> > >
> > >    def supported_collections
> > >      DEFAULT_COLLECTIONS + [ :addresses, :load_balancers,
:firewalls ]
> > > --
> > > 1.7.10.1
> > >
> >
> >
> 
> --
> Michal Fojtik
> Sr. Software Engineer, Deltacloud API (http://deltacloud.org)



Re: [PATCH core 49/51] FGCP: Renamed the driver class to be loadable and removed DEFAULT_CONFIG constant, because it's not longer set

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/21/12, Koper, Dies wrote:
> Hi Michal,
> 
> > -  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> > File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
> > +  CERT_DIR = ENV['FGCP_CERT_DIR']
> 
> I thought that we agreed on IRC to use something like
> +  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> File::expand_path('~\.deltacloud\config\fgcp')
> ?

Right. I'll add that before push, thanks for reminding me.

  -- Michal

> 
> Regards,
> Dies Koper
> 
> 
> 
> > -----Original Message-----
> > From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> > Sent: Monday, 21 May 2012 8:08 PM
> > To: dev@deltacloud.apache.org
> > Subject: [PATCH core 49/51] FGCP: Renamed the driver class to be
> loadable
> > and removed DEFAULT_CONFIG constant, because it's not longer set
> > 
> > From: Michal Fojtik <mf...@redhat.com>
> > 
> > 
> > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > ---
> >  server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    1 -
> >  server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    9 ++++-----
> >  2 files changed, 4 insertions(+), 6 deletions(-)
> > 
> > diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > index 9072c84..b0e1897 100644
> > --- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> > @@ -15,7 +15,6 @@
> >  #
> >  # Author: Dies Koper <di...@fast.au.fujitsu.com>
> > 
> > -require 'deltacloud/base_driver'
> >  require 'net/http'
> >  require 'net/https'
> >  require 'rubygems'
> > diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > index 93ab8fa..4d65e7c 100644
> > --- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> > @@ -15,17 +15,16 @@
> >  #
> >  # Author: Dies Koper <di...@fast.au.fujitsu.com>
> > 
> > -require 'deltacloud/base_driver'
> > -require 'deltacloud/drivers/fgcp/fgcp_client'
> > +require_relative 'fgcp_client'
> >  require 'openssl'
> >  require 'xmlsimple'
> > 
> >  module Deltacloud
> >    module Drivers
> > -    module FGCP
> > -class FGCPDriver < Deltacloud::BaseDriver
> > +    module Fgcp
> > +class FgcpDriver < Deltacloud::BaseDriver
> > 
> > -  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> > File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
> > +  CERT_DIR = ENV['FGCP_CERT_DIR']
> > 
> >    def supported_collections
> >      DEFAULT_COLLECTIONS + [ :addresses, :load_balancers, :firewalls ]
> > --
> > 1.7.10.1
> > 
> 
> 

-- 
Michal Fojtik
Sr. Software Engineer, Deltacloud API (http://deltacloud.org)

RE: [PATCH core 49/51] FGCP: Renamed the driver class to be loadable and removed DEFAULT_CONFIG constant, because it's not longer set

Posted by "Koper, Dies" <di...@fast.au.fujitsu.com>.
Hi Michal,

> -  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
> +  CERT_DIR = ENV['FGCP_CERT_DIR']

I thought that we agreed on IRC to use something like
+  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
File::expand_path('~\.deltacloud\config\fgcp')
?

Regards,
Dies Koper



> -----Original Message-----
> From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> Sent: Monday, 21 May 2012 8:08 PM
> To: dev@deltacloud.apache.org
> Subject: [PATCH core 49/51] FGCP: Renamed the driver class to be
loadable
> and removed DEFAULT_CONFIG constant, because it's not longer set
> 
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    1 -
>  server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    9 ++++-----
>  2 files changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> index 9072c84..b0e1897 100644
> --- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
> @@ -15,7 +15,6 @@
>  #
>  # Author: Dies Koper <di...@fast.au.fujitsu.com>
> 
> -require 'deltacloud/base_driver'
>  require 'net/http'
>  require 'net/https'
>  require 'rubygems'
> diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> index 93ab8fa..4d65e7c 100644
> --- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> +++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
> @@ -15,17 +15,16 @@
>  #
>  # Author: Dies Koper <di...@fast.au.fujitsu.com>
> 
> -require 'deltacloud/base_driver'
> -require 'deltacloud/drivers/fgcp/fgcp_client'
> +require_relative 'fgcp_client'
>  require 'openssl'
>  require 'xmlsimple'
> 
>  module Deltacloud
>    module Drivers
> -    module FGCP
> -class FGCPDriver < Deltacloud::BaseDriver
> +    module Fgcp
> +class FgcpDriver < Deltacloud::BaseDriver
> 
> -  CERT_DIR = ENV['FGCP_CERT_DIR'] ||
> File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
> +  CERT_DIR = ENV['FGCP_CERT_DIR']
> 
>    def supported_collections
>      DEFAULT_COLLECTIONS + [ :addresses, :load_balancers, :firewalls ]
> --
> 1.7.10.1
> 



[PATCH core 49/51] FGCP: Renamed the driver class to be loadable and removed DEFAULT_CONFIG constant, because it's not longer set

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    1 -
 server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    9 ++++-----
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
index 9072c84..b0e1897 100644
--- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
+++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
@@ -15,7 +15,6 @@
 #
 # Author: Dies Koper <di...@fast.au.fujitsu.com>
 
-require 'deltacloud/base_driver'
 require 'net/http'
 require 'net/https'
 require 'rubygems'
diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
index 93ab8fa..4d65e7c 100644
--- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
+++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
@@ -15,17 +15,16 @@
 #
 # Author: Dies Koper <di...@fast.au.fujitsu.com>
 
-require 'deltacloud/base_driver'
-require 'deltacloud/drivers/fgcp/fgcp_client'
+require_relative 'fgcp_client'
 require 'openssl'
 require 'xmlsimple'
 
 module Deltacloud
   module Drivers
-    module FGCP
-class FGCPDriver < Deltacloud::BaseDriver
+    module Fgcp
+class FgcpDriver < Deltacloud::BaseDriver
 
-  CERT_DIR = ENV['FGCP_CERT_DIR'] || File::expand_path(File::join(DEFAULT_CONFIG, 'fgcp'))
+  CERT_DIR = ENV['FGCP_CERT_DIR']
 
   def supported_collections
     DEFAULT_COLLECTIONS + [ :addresses, :load_balancers, :firewalls ]
-- 
1.7.10.1


[PATCH core 06/51] Core: Added the :name property to Deltacloud Key model

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/views/keys/show.xml.haml |    1 +
 1 file changed, 1 insertion(+)

diff --git a/server/views/keys/show.xml.haml b/server/views/keys/show.xml.haml
index abb513b..2e98d0d 100644
--- a/server/views/keys/show.xml.haml
+++ b/server/views/keys/show.xml.haml
@@ -1,6 +1,7 @@
 - unless defined?(partial)
   !!! XML
 %key{ :href => key_url(@key.id), :id => @key.id, :type => "#{@key.credential_type}" }
+  %name=@key.name
   %actions
     - if driver.respond_to?(:destroy_key)
       %link{ :rel => "destroy", :method => "delete", :href => destroy_key_url(@key.id)}
-- 
1.7.10.1


[PATCH core 31/51] FGCP: Fixed the driver to use :default in entrypoint configuration

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/drivers/fgcp/fgcp_client.rb |    2 +-
 server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
index 534979d..c544998 100644
--- a/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
+++ b/server/lib/deltacloud/drivers/fgcp/fgcp_client.rb
@@ -35,7 +35,7 @@ class FGCPClient
     @locale = locale
     cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
     country = $1.downcase
-    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][country] unless endpoint
+    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][:default][country] unless endpoint
     raise "API endpoint not found for region #{country}" if endpoint.nil?
 
     #proxy settings:
diff --git a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
index 6f8b9bd..0729ae4 100644
--- a/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
+++ b/server/lib/deltacloud/drivers/fgcp/fgcp_driver.rb
@@ -1136,7 +1136,7 @@ eofwopxml
     cert, key = convert_credentials(credentials)
     cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
     country = $1.downcase
-    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][country]
+    endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints][:default][country]
     [
       Provider.new(
         :id => "fgcp-#{country}",
-- 
1.7.10.1


[PATCH core 23/51] Core: Added the minitest gem to the Gemfile for MRI 1.8

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Gemfile |    1 +
 1 file changed, 1 insertion(+)

diff --git a/server/Gemfile b/server/Gemfile
index 1750bdd..244814c 100644
--- a/server/Gemfile
+++ b/server/Gemfile
@@ -10,5 +10,6 @@ group :development do
   gem "ci_reporter"
   gem "cucumber", ">= 0.6.3"
   gem "rspec", ">= 2.0.0"
+  gem "minitest"
 end
 
-- 
1.7.10.1


[PATCH core 10/51] Core: Renamed @profiles to @hardware_profiles to make standard operation helpers work

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/views/hardware_profiles/index.html.haml |    2 +-
 server/views/hardware_profiles/index.xml.haml  |    4 ++--
 server/views/hardware_profiles/show.html.haml  |    6 +++---
 server/views/hardware_profiles/show.xml.haml   |    6 +++---
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/server/views/hardware_profiles/index.html.haml b/server/views/hardware_profiles/index.html.haml
index 64e3455..59d43eb 100644
--- a/server/views/hardware_profiles/index.html.haml
+++ b/server/views/hardware_profiles/index.html.haml
@@ -3,7 +3,7 @@
 
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview, :'data-inset' => :true }
-    - for profile in @profiles
+    - for profile in @hardware_profiles
       %li{ :'data-theme' => 'c'}
         %a{ :href => hardware_profile_url(profile.name)}
           %img{ :class => 'ui-link-thumb', :src => '/images/profile.png'}
diff --git a/server/views/hardware_profiles/index.xml.haml b/server/views/hardware_profiles/index.xml.haml
index cf0a69f..25e0496 100644
--- a/server/views/hardware_profiles/index.xml.haml
+++ b/server/views/hardware_profiles/index.xml.haml
@@ -1,4 +1,4 @@
 !!! XML
 %hardware_profiles
-  - @profiles.each do |prof|
-    = haml :'hardware_profiles/show', :locals => { :@profile => prof, :partial => true }
+  - @hardware_profiles.each do |prof|
+    = haml :'hardware_profiles/show', :locals => { :@hardware_profile => prof, :partial => true }
diff --git a/server/views/hardware_profiles/show.html.haml b/server/views/hardware_profiles/show.html.haml
index c27690e..033e94d 100644
--- a/server/views/hardware_profiles/show.html.haml
+++ b/server/views/hardware_profiles/show.html.haml
@@ -1,12 +1,12 @@
 =header "Hardware profiles"
-=subheader @profile.name
+=subheader @hardware_profile.name
 
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview , :'data-inset' => :true, :'data-divider-theme' => 'd'}
     %li{ :'data-role' => 'list-divider'} Name
     %li
-      %p{ :'data-role' => 'fieldcontain'}=@profile.name
-    - @profile.each_property do |p|
+      %p{ :'data-role' => 'fieldcontain'}=@hardware_profile.name
+    - @hardware_profile.each_property do |p|
       %li{ :'data-role' => 'list-divider'} #{p.name.to_s.titlecase}
       %li
         %p{ :'data-role' => 'fieldcontain'}
diff --git a/server/views/hardware_profiles/show.xml.haml b/server/views/hardware_profiles/show.xml.haml
index 094ffd5..21e488c 100644
--- a/server/views/hardware_profiles/show.xml.haml
+++ b/server/views/hardware_profiles/show.xml.haml
@@ -1,9 +1,9 @@
 - unless defined?(partial)
   !!! XML
-%hardware_profile{ :href => hardware_profile_url(@profile.name), :id => @profile.name }
+%hardware_profile{ :href => hardware_profile_url(@hardware_profile.name), :id => @hardware_profile.name }
   %name<
-    =@profile.name
-  - @profile.each_property do |prop|
+    = @hardware_profile.name
+  - @hardware_profile.each_property do |prop|
     - attr = { :name => prop.name, :kind => prop.kind, :unit => prop.unit }
     - if prop.kind == :fixed
       %property{ attr, :value => prop.value }/
-- 
1.7.10.1


[PATCH core 25/51] SBC: Fixed cucumber scenatios to work with Sinatra::Base

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 tests/sbc/step_definitions/common_steps.rb |    2 +
 tests/sbc/support/env.rb                   |   82 ++++++++++++----------------
 2 files changed, 36 insertions(+), 48 deletions(-)

diff --git a/tests/sbc/step_definitions/common_steps.rb b/tests/sbc/step_definitions/common_steps.rb
index a9cf8e4..d5f9c15 100644
--- a/tests/sbc/step_definitions/common_steps.rb
+++ b/tests/sbc/step_definitions/common_steps.rb
@@ -1,3 +1,5 @@
+World(Rack::Test::Methods)
+
 Given /^I enter ([A-Za-z_]+) collection$/ do |collection|
   @current_collection = collection
   @current_collection_url = "/api/%s" % collection.strip
diff --git a/tests/sbc/support/env.rb b/tests/sbc/support/env.rb
index 2ca8cb4..fe27329 100644
--- a/tests/sbc/support/env.rb
+++ b/tests/sbc/support/env.rb
@@ -1,67 +1,53 @@
-SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
+require 'rubygems'
+require 'nokogiri'
 
+SERVER_DIR = File::expand_path(File::join(File::dirname(__FILE__), "../../../server"))
 $top_srcdir = SERVER_DIR
 $:.unshift File::join($top_srcdir, 'lib')
-
-ENV['API_DRIVER'] = 'sbc'
-
 Dir.chdir(SERVER_DIR)
 
-require 'rubygems'
-require 'nokogiri'
-require 'deltacloud/server'
-require 'rack/test'
-
-Sinatra::Application.set :environment, :test
-Sinatra::Application.set :root, SERVER_DIR
-
-CONFIG = {
-  :username => 'sbc_test_username',
-  :password => 'sbc_test_password'
-}
-
-ENV['RACK_ENV'] = 'test'
+API_VERSION = "9.9.9"
+API_ROOT_URL = "/api"
 
+ENV['API_DRIVER'] = 'sbc'
+ENV.delete('API_VERBOSE')
 
-World do
+load File.join($top_srcdir, 'lib', 'deltacloud', 'server.rb')
 
-  include Rack::Test::Methods
+require 'rack/test'
 
-  module Rack
-    module Test
-      class Session
-        def headers
-          @headers
-        end
-      end
-    end
-    class MockSession
-      def set_last_response(response)
-        @last_response = response
+module Rack
+  module Test
+    class Session
+      def headers
+        @headers
       end
     end
   end
-
-  def app
-    @app = Rack::Builder.new do
-      set :environment => :development
-      set :loggining => true
-      set :raise_errors => true
-      set :show_exceptions => true
-      run Sinatra::Application
+  class MockSession
+    def set_last_response(response)
+      @last_response = response
     end
   end
+end
 
-  def xml
-    Nokogiri::XML(last_response.body)
-  end
-
+CONFIG = {
+  :username => 'mockuser',
+  :password => 'mockpassword'
+}
 
+def output_xml
+  Nokogiri::XML(last_response.body)
+end
 
-  Before do
-    unless @no_header
-      header 'Accept', 'application/xml;q=9'
-    end
-  end
+def xml
+  Nokogiri::XML(last_response.body)
+end
 
+def app
+  Rack::URLMap.new(
+    "/" => Deltacloud::API.new,
+    "/stylesheets" =>  Rack::Directory.new( "public/stylesheets" ),
+    "/javascripts" =>  Rack::Directory.new( "public/javascripts" )
+  )
 end
-- 
1.7.10.1


[PATCH core 38/51] CIMI: Fixed feature loading in entity_metadata model

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/helpers.rb                |    2 +-
 server/lib/cimi/models/entity_metadata.rb |    3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/server/lib/cimi/helpers.rb b/server/lib/cimi/helpers.rb
index 05d2621..5fe8cf8 100644
--- a/server/lib/cimi/helpers.rb
+++ b/server/lib/cimi/helpers.rb
@@ -26,7 +26,7 @@ module CIMI
 
   class FakeCollection
     extend Sinatra::Rabbit::Features
-    include Deltacloud::InstanceFeatures
+    include Deltacloud::Features
   end
 end
 
diff --git a/server/lib/cimi/models/entity_metadata.rb b/server/lib/cimi/models/entity_metadata.rb
index 5455c75..c14f3c2 100644
--- a/server/lib/cimi/models/entity_metadata.rb
+++ b/server/lib/cimi/models/entity_metadata.rb
@@ -52,7 +52,8 @@ class CIMI::Model::EntityMetadata < CIMI::Model::Base
   end
 
   def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
-    deltacloud_features = context.driver.class.features_for(dcloud_entity)
+    deltacloud_features = context.driver.class.features[dcloud_entity]
+    puts deltacloud_features.inspect
     metadata_attributes = deltacloud_features.map{|f| attributes_from_feature(f)}
     from_feature(cimi_entity, context, metadata_attributes.flatten!)
   end
-- 
1.7.10.1


[PATCH core 08/51] Core: Added sinatra helper to include all Rack and Sinatra middleware

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/sinatra.rb                        |   21 +++++++++++++++++++++
 server/views/storage_snapshots/show.xml.haml |    4 +---
 2 files changed, 22 insertions(+), 3 deletions(-)
 create mode 100644 server/lib/sinatra.rb

diff --git a/server/lib/sinatra.rb b/server/lib/sinatra.rb
new file mode 100644
index 0000000..6179d55
--- /dev/null
+++ b/server/lib/sinatra.rb
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require_relative 'sinatra/rack_date'
+require_relative 'sinatra/rack_etag'
+require_relative 'sinatra/rack_matrix_params'
+require_relative 'sinatra/rack_driver_select'
+require_relative 'sinatra/accept_media_types'
+require_relative 'sinatra/rack_accept'
diff --git a/server/views/storage_snapshots/show.xml.haml b/server/views/storage_snapshots/show.xml.haml
index c151c1e..a47a652 100644
--- a/server/views/storage_snapshots/show.xml.haml
+++ b/server/views/storage_snapshots/show.xml.haml
@@ -1,9 +1,7 @@
 - unless defined?(partial)
   !!! XML
 %storage_snapshot{:href => storage_snapshot_url(@storage_snapshot.id), :id => @storage_snapshot.id }
+  %name=@storage_snapshot.id
   %created<
     =@storage_snapshot.created
   %storage_volume{:href => storage_volume_url(@storage_snapshot.storage_volume_id), :id => @storage_snapshot.storage_volume_id}
-  %actions
-    - if driver.respond_to? :destroy_storage_snapshot
-      %link{:rel => :destroy, :method => :delete, :href => destroy_storage_snapshot_url(@storage_snapshot.id)}
-- 
1.7.10.1


[PATCH core 36/51] Core: Fixed advertising of collection features other than instances

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/buckets.rb    |    9 +++----
 server/lib/deltacloud/collections/images.rb     |    3 +++
 server/lib/deltacloud/collections/instances.rb  |    2 +-
 server/lib/deltacloud/drivers/base_driver.rb    |    7 ++---
 server/lib/deltacloud/drivers/ec2/ec2_driver.rb |    4 +--
 server/lib/deltacloud/drivers/features.rb       |   31 ++++++++++++++++++++++-
 6 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/server/lib/deltacloud/collections/buckets.rb b/server/lib/deltacloud/collections/buckets.rb
index 3a5591d..16f3f8f 100644
--- a/server/lib/deltacloud/collections/buckets.rb
+++ b/server/lib/deltacloud/collections/buckets.rb
@@ -15,14 +15,13 @@
 
 module Deltacloud::Collections
   class Buckets < Base
+
+    include Deltacloud::Features
+
     check_capability :for => lambda { |m| driver.respond_to? m }
     check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
 
-    get route_for('/buckets/new') do
-      respond_to do |format|
-        format.html { haml :"buckets/new" }
-      end
-    end
+    new_route_for :buckets
 
     get route_for('/buckets/:bucket/%s' % NEW_BLOB_FORM_ID) do
       @bucket_id = params[:bucket]
diff --git a/server/lib/deltacloud/collections/images.rb b/server/lib/deltacloud/collections/images.rb
index c8b3e08..0edd7c0 100644
--- a/server/lib/deltacloud/collections/images.rb
+++ b/server/lib/deltacloud/collections/images.rb
@@ -15,6 +15,9 @@
 
 module Deltacloud::Collections
   class Images < Base
+
+    include Deltacloud::Features
+
     check_capability :for => lambda { |m| driver.respond_to? m }
     check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
 
diff --git a/server/lib/deltacloud/collections/instances.rb b/server/lib/deltacloud/collections/instances.rb
index 0da94f2..bba2ef9 100644
--- a/server/lib/deltacloud/collections/instances.rb
+++ b/server/lib/deltacloud/collections/instances.rb
@@ -16,7 +16,7 @@
 module Deltacloud::Collections
   class Instances < Base
 
-    include Deltacloud::InstanceFeatures
+    include Deltacloud::Features
 
     check_capability :for => lambda { |m| driver.respond_to? m }
     check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb
index 9913c27..a360807 100644
--- a/server/lib/deltacloud/drivers/base_driver.rb
+++ b/server/lib/deltacloud/drivers/base_driver.rb
@@ -30,7 +30,7 @@ module Deltacloud
     end
 
     def self.features
-      @features ||= []
+      @features ||= {}
     end
 
     def self.features_for(entity)
@@ -45,7 +45,8 @@ module Deltacloud
       constraints[collection] ||= {}
       constraints[collection][feature_name] ||= {}
       constraints[collection][feature_name].merge!(yield) if block_given?
-      features << { collection => feature_name }
+      features[collection] ||= []
+      features[collection] << feature_name
     end
 
     def self.constraints(opts={})
@@ -57,7 +58,7 @@ module Deltacloud
     end
 
     def self.has_feature?(collection, feature_name)
-      features.any? { |f| (f.values.first == feature_name) && (f.keys.first == collection) }
+      features.has_key?(collection) and features[collection].include?(feature_name)
     end
 
     def name
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index f7559a3..b55132e 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -36,8 +36,8 @@ module Deltacloud
         feature :instances, :firewalls
         feature :instances, :instance_count
         feature :images, :owner_id
-        feature :images, :user_name
-        feature :images, :user_description
+        feature :images, :image_name
+        feature :images, :image_description
         feature :buckets, :bucket_location
         feature :instances, :attach_snapshot
 
diff --git a/server/lib/deltacloud/drivers/features.rb b/server/lib/deltacloud/drivers/features.rb
index 01d8656..c772a42 100644
--- a/server/lib/deltacloud/drivers/features.rb
+++ b/server/lib/deltacloud/drivers/features.rb
@@ -14,7 +14,8 @@
 # under the License.
 
 module Deltacloud
-  module InstanceFeatures
+
+  module Features
 
     def self.included(k)
       current_features = features
@@ -29,6 +30,34 @@ module Deltacloud
 
     features do
 
+      feature :owner_id, :for => :images do
+        description "Filter images using owner id"
+        operation :index do
+          param :owner_id,  :string,  :optional,  [],  "Owner ID"
+        end
+      end
+
+      feature :image_name, :for => :images do
+        description "Allow specifying user name for created image"
+        operation :create do
+          param :name,  :string,  :optional,  [],  "Image name"
+        end
+      end
+
+      feature :image_description, :for => :images do
+        description "Allow specifying user description for created image"
+        operation :create do
+          param :description, :string,  :optional,  [],  "Image description"
+        end
+      end
+
+      feature :bucket_location, :for => :buckets do
+        description "Take extra location parameter for Bucket creation (e.g. S3, 'eu' or 'us-west-1')"
+        operation :create do
+          param :location, :string, :optional
+        end
+      end
+
       feature :user_name, :for => :instances do
         description "Allow to set user-defined name for the instance"
         operation :create do
-- 
1.7.10.1


[PATCH core 37/51] CIMI: Fixed the rspec and cucumber tests to work fine with new server layout

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/collections/cloud_entry_point.rb   |    9 +++-
 server/lib/cimi/collections/machines.rb            |    4 +-
 server/lib/cimi/helpers.rb                         |   22 ++++++----
 server/lib/cimi/models.rb                          |   15 +++----
 server/lib/cimi/models/volume.rb                   |    2 +-
 server/lib/cimi/server.rb                          |    9 +---
 server/lib/deltacloud_rack.rb                      |    4 +-
 server/spec/spec_helper.rb                         |    6 ++-
 .../features/step_definitions/machines_steps.rb    |    1 +
 .../features/step_definitions/volumes_steps.rb     |    4 +-
 server/tests/cimi/features/support/env.rb          |   44 +++++++++++++++-----
 11 files changed, 75 insertions(+), 45 deletions(-)

diff --git a/server/lib/cimi/collections/cloud_entry_point.rb b/server/lib/cimi/collections/cloud_entry_point.rb
index 8232e61..f5f2233 100644
--- a/server/lib/cimi/collections/cloud_entry_point.rb
+++ b/server/lib/cimi/collections/cloud_entry_point.rb
@@ -23,7 +23,14 @@ module CIMI::Collections
       operation :index do
         description "list all resources of the cloud"
         control do
-          redirect Deltacloud[:root_url]
+          if params[:force_auth]
+            return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
+          end
+          entry_point = CIMI::Model::CloudEntryPoint.create(self)
+          respond_to do |format|
+            format.xml { entry_point.to_xml }
+            format.json { entry_point.to_json }
+          end
         end
       end
     end
diff --git a/server/lib/cimi/collections/machines.rb b/server/lib/cimi/collections/machines.rb
index 0abf63a..cadbcad 100644
--- a/server/lib/cimi/collections/machines.rb
+++ b/server/lib/cimi/collections/machines.rb
@@ -85,7 +85,7 @@ module CIMI::Collections
         end
       end
 
-      operation :restart do
+      action :restart do
         description "Start specific machine."
         control do
           machine = Machine.find(params[:id], self)
@@ -101,7 +101,7 @@ module CIMI::Collections
         end
       end
 
-      operation :start do
+      action :start do
         description "Start specific machine."
         control do
           machine = Machine.find(params[:id], self)
diff --git a/server/lib/cimi/helpers.rb b/server/lib/cimi/helpers.rb
index b0fc9e3..05d2621 100644
--- a/server/lib/cimi/helpers.rb
+++ b/server/lib/cimi/helpers.rb
@@ -16,20 +16,28 @@
 module Deltacloud; end
 module CIMI; end
 
+require_relative '../deltacloud/drivers/features'
+
+# Declare namespace for CIMI models
+#
+
+module CIMI
+  module Model; end
+
+  class FakeCollection
+    extend Sinatra::Rabbit::Features
+    include Deltacloud::InstanceFeatures
+  end
+end
+
 require_relative '../deltacloud/drivers'
 require_relative '../deltacloud/models'
 require_relative '../deltacloud/helpers/driver_helper'
 require_relative '../deltacloud/helpers/auth_helper'
 require_relative '../deltacloud/helpers/url_helper'
-require_relative '../deltacloud/helpers/assets_helper'
 require_relative '../deltacloud/helpers/deltacloud_helper'
 require_relative '../deltacloud/helpers/rabbit_helper'
 require_relative '../deltacloud/helpers/rabbit_helper'
-require_relative '../deltacloud/core_ext/string'
-require_relative '../deltacloud/core_ext/array'
-require_relative '../deltacloud/core_ext/hash'
-require_relative '../deltacloud/core_ext/integer'
-require_relative '../deltacloud/core_ext/proc'
 require_relative './helpers/cimi_helper'
 require_relative './models'
 
@@ -43,9 +51,9 @@ module CIMI::Collections
     helpers Deltacloud::Helpers::Drivers
     helpers Sinatra::AuthHelper
     helpers Sinatra::UrlForHelper
-    helpers Sinatra::StaticAssets::Helpers
     helpers Rack::RespondTo::Helpers
     helpers Deltacloud::Helpers::Application
+    helpers CIMIHelper
 
     register Rack::RespondTo
 
diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
index b0793ee..1214497 100644
--- a/server/lib/cimi/models.rb
+++ b/server/lib/cimi/models.rb
@@ -13,18 +13,15 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 #
-
-require_relative '../deltacloud/drivers/features'
-
-# Declare namespace for CIMI models
-#
-
 module CIMI
   module Model; end
+end
 
-  class FakeCollection
-    extend Sinatra::Rabbit::Features
-    include Deltacloud::InstanceFeatures
+unless Kernel.respond_to?(:require_relative)
+  module Kernel
+    def require_relative(path)
+      require File.join(File.dirname(caller[0]), path.to_str)
+    end
   end
 end
 
diff --git a/server/lib/cimi/models/volume.rb b/server/lib/cimi/models/volume.rb
index 9c106e2..111a4e5 100644
--- a/server/lib/cimi/models/volume.rb
+++ b/server/lib/cimi/models/volume.rb
@@ -81,7 +81,7 @@ class CIMI::Model::Volume < CIMI::Model::Base
   def self.create_volume(params, context)
     volume_config = CIMI::Model::VolumeConfiguration.find(params[:volume_config_id], context)
     opts = {:capacity=>volume_config.capacity[:quantity], :snapshot_id=>params[:volume_image_id] }
-    storage_volume = self.driver.create_storage_volume(context.credentials, opts)
+    storage_volume = context.driver.create_storage_volume(context.credentials, opts)
     from_storage_volume(storage_volume, context)
   end
 
diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
index c34dba9..58c1688 100644
--- a/server/lib/cimi/server.rb
+++ b/server/lib/cimi/server.rb
@@ -46,14 +46,7 @@ module CIMI
     include CIMI::Model
 
     get Deltacloud[:root_url] do
-      if params[:force_auth]
-        return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
-      end
-      entry_point = CIMI::Model::CloudEntryPoint.create(self)
-      respond_to do |format|
-        format.xml { entry_point.to_xml }
-        format.json { entry_point.to_json }
-      end
+      redirect Deltacloud[:root_url] + '/cloudEntryPoint', 301
     end
 
   end
diff --git a/server/lib/deltacloud_rack.rb b/server/lib/deltacloud_rack.rb
index b795731..a52354c 100644
--- a/server/lib/deltacloud_rack.rb
+++ b/server/lib/deltacloud_rack.rb
@@ -34,7 +34,7 @@ module Deltacloud
   end
 
   def self.configure(&block)
-    config(Server.new(&block))
+    @config = Server.new(&block)
     self
   end
 
@@ -45,7 +45,7 @@ module Deltacloud
   def self.require_frontend!
     ENV['API_FRONTEND'] ||= 'deltacloud'
     require File.join(File.dirname(__FILE__), ENV['API_FRONTEND'], 'server.rb')
-    config.klass eval(self[:klass])
+    config.klass eval('::'+self[:klass])
   end
 
   class Server
diff --git a/server/spec/spec_helper.rb b/server/spec/spec_helper.rb
index 8599a71..22809e2 100644
--- a/server/spec/spec_helper.rb
+++ b/server/spec/spec_helper.rb
@@ -17,10 +17,12 @@
 require 'rubygems'
 require 'pp'
 require 'rspec/core'
-require 'deltacloud/core_ext'
-require 'cimi/model'
 require 'xmlsimple'
 
+load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud', 'core_ext', 'array.rb')
+load File.join(File.dirname(__FILE__), '..', 'lib', 'deltacloud', 'core_ext', 'string.rb')
+load File.join(File.dirname(__FILE__), '..', 'lib', 'cimi', 'models.rb')
+
 DATA_DIR = File::join(File::expand_path(File::dirname(__FILE__)), 'cimi', 'data')
 
 def parse_xml(xml, opts = {})
diff --git a/server/tests/cimi/features/step_definitions/machines_steps.rb b/server/tests/cimi/features/step_definitions/machines_steps.rb
index 0843ccf..c11d535 100644
--- a/server/tests/cimi/features/step_definitions/machines_steps.rb
+++ b/server/tests/cimi/features/step_definitions/machines_steps.rb
@@ -82,6 +82,7 @@ When /^client executes (\w+) operation on created Machine$/ do |operation|
   header 'Content-Type', 'application/xml'
   if operation == 'delete'
     delete "/cimi/machines/%s" % new_machine.name
+    puts last_response.body
     last_response.status.should == 200
     last_response.body.should be_empty
     @delete_operation = true
diff --git a/server/tests/cimi/features/step_definitions/volumes_steps.rb b/server/tests/cimi/features/step_definitions/volumes_steps.rb
index 9aa6ea2..fc93be0 100644
--- a/server/tests/cimi/features/step_definitions/volumes_steps.rb
+++ b/server/tests/cimi/features/step_definitions/volumes_steps.rb
@@ -37,7 +37,7 @@ When /^client GET the Volumes Collection$/ do
   header 'Content-Type', 'application/xml'
   get "/cimi/volumes"
   last_response.status.should == 200
-  @@volume_collection = VolumeCollection.from_xml(last_response.body)
+  @@volume_collection = CIMI::Model::VolumeCollection.from_xml(last_response.body)
 end
 
 Then /^client should get a list of volumes$/ do
@@ -69,7 +69,7 @@ When /^client specifies a running Machine using$/ do |machine|
   header 'Content-Type', 'application/xml'
   get "/cimi/machines/#{@machine_id}?format=xml"
   last_response.status.should==200
-  @@machine = Machine.from_xml(last_response.body)
+  @@machine = CIMI::Model::Machine.from_xml(last_response.body)
   @@machine.name.should == @machine_id
   @@machine.state.should == "STARTED"
 end
diff --git a/server/tests/cimi/features/support/env.rb b/server/tests/cimi/features/support/env.rb
index c5e2bf0..f8372bf 100644
--- a/server/tests/cimi/features/support/env.rb
+++ b/server/tests/cimi/features/support/env.rb
@@ -1,21 +1,47 @@
 require 'rubygems'
 require 'nokogiri'
+require 'rack/test'
 
-ENV['API_DRIVER'] = 'mock'
 ENV['API_FRONTEND'] = 'cimi'
-ENV.delete('API_VERBOSE')
-
-$top_srcdir = File.join(File.dirname(__FILE__), '..', '..', '..', '..')
-$:.unshift File.join($top_srcdir, 'lib')
 
-load File.join($top_srcdir, 'lib', 'cimi', 'server.rb')
+load File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'lib', 'deltacloud_rack.rb')
 
-require 'rack/test'
+Deltacloud::configure do |server|
+  server.root_url '/cimi'
+  server.version '1.0.0'
+  server.klass 'CIMI::API'
+end.require_frontend!
 
 def last_xml_response
   Nokogiri::XML(last_response.body)
 end
 
+class IndexEntrypoint < Sinatra::Base
+  get "/" do
+    redirect Deltacloud[:root_url], 301
+  end
+end
+
+=begin
+def app
+  Rack::URLMap.new(
+    "/" => IndexEntrypoint.new,
+    Deltacloud[:root_url] => CIMI::API,
+    "/stylesheets" =>  Rack::Directory.new( "public/stylesheets" ),
+    "/javascripts" =>  Rack::Directory.new( "public/javascripts" )
+  )
+end
+=end
+
+def app
+  Rack::Builder.new {
+    map '/' do
+      use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+      run Rack::Cascade.new([CIMI::API])
+    end
+  }
+end
+
 def new_machine
   @@new_machine
 end
@@ -47,7 +73,3 @@ class String
   end
 
 end
-
-def app
-  Sinatra::Application
-end
-- 
1.7.10.1


[PATCH core 02/51] Core: Added new Sinatra::Base Deltacloud collection based on Sinatra::Rabbit

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/config.ru                                   |   41 ++-
 server/lib/deltacloud/base_driver/base_driver.rb   |  250 ------------------
 server/lib/deltacloud/base_driver/exceptions.rb    |  191 --------------
 server/lib/deltacloud/base_driver/features.rb      |  276 --------------------
 server/lib/deltacloud/collections.rb               |   54 ++++
 server/lib/deltacloud/collections/addresses.rb     |   83 ++++++
 server/lib/deltacloud/collections/buckets.rb       |  215 +++++++++++++++
 server/lib/deltacloud/collections/drivers.rb       |   51 ++++
 server/lib/deltacloud/collections/firewalls.rb     |  116 ++++++++
 .../deltacloud/collections/hardware_profiles.rb    |   27 ++
 server/lib/deltacloud/collections/images.rb        |   70 +++++
 .../lib/deltacloud/collections/instance_states.rb  |   57 ++++
 server/lib/deltacloud/collections/instances.rb     |  103 ++++++++
 server/lib/deltacloud/collections/keys.rb          |   61 +++++
 .../lib/deltacloud/collections/load_balancers.rb   |   85 ++++++
 server/lib/deltacloud/collections/realms.rb        |   27 ++
 .../deltacloud/collections/storage_snapshots.rb    |   51 ++++
 .../lib/deltacloud/collections/storage_volumes.rb  |   99 +++++++
 server/lib/deltacloud/drivers/base_driver.rb       |  265 +++++++++++++++++++
 .../drivers/eucalyptus/eucalyptus_driver.rb        |    2 +-
 server/lib/deltacloud/drivers/exceptions.rb        |  191 ++++++++++++++
 .../drivers/opennebula/opennebula_driver.rb        |    1 -
 .../drivers/rimuhosting/rimuhosting_client.rb      |   97 ++++---
 .../drivers/rimuhosting/rimuhosting_driver.rb      |    4 +-
 .../drivers/terremark/terremark_driver.rb          |    5 +-
 server/lib/deltacloud/helpers.rb                   |   86 +++++-
 server/lib/deltacloud/models.rb                    |   26 +-
 server/lib/deltacloud/models/hardware_profile.rb   |  194 ++++++++++++++
 server/lib/deltacloud/models/state_machine.rb      |   99 +++++++
 server/lib/deltacloud/state_machine.rb             |  115 --------
 30 files changed, 2021 insertions(+), 921 deletions(-)
 delete mode 100644 server/lib/deltacloud/base_driver/base_driver.rb
 delete mode 100644 server/lib/deltacloud/base_driver/exceptions.rb
 delete mode 100644 server/lib/deltacloud/base_driver/features.rb
 create mode 100644 server/lib/deltacloud/collections.rb
 create mode 100644 server/lib/deltacloud/collections/addresses.rb
 create mode 100644 server/lib/deltacloud/collections/buckets.rb
 create mode 100644 server/lib/deltacloud/collections/drivers.rb
 create mode 100644 server/lib/deltacloud/collections/firewalls.rb
 create mode 100644 server/lib/deltacloud/collections/hardware_profiles.rb
 create mode 100644 server/lib/deltacloud/collections/images.rb
 create mode 100644 server/lib/deltacloud/collections/instance_states.rb
 create mode 100644 server/lib/deltacloud/collections/instances.rb
 create mode 100644 server/lib/deltacloud/collections/keys.rb
 create mode 100644 server/lib/deltacloud/collections/load_balancers.rb
 create mode 100644 server/lib/deltacloud/collections/realms.rb
 create mode 100644 server/lib/deltacloud/collections/storage_snapshots.rb
 create mode 100644 server/lib/deltacloud/collections/storage_volumes.rb
 create mode 100644 server/lib/deltacloud/drivers/base_driver.rb
 create mode 100644 server/lib/deltacloud/drivers/exceptions.rb
 create mode 100644 server/lib/deltacloud/models/hardware_profile.rb
 create mode 100644 server/lib/deltacloud/models/state_machine.rb
 delete mode 100644 server/lib/deltacloud/state_machine.rb

diff --git a/server/config.ru b/server/config.ru
index a1f9efd..87d9506 100644
--- a/server/config.ru
+++ b/server/config.ru
@@ -14,14 +14,43 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'rubygems'
+# The default URL prefix (where to mount Deltacloud API)
 
-$top_srcdir ||= File::expand_path(File.dirname(__FILE__))
+# The default driver is 'mock'
+ENV['API_DRIVER'] ||= 'mock'
 
-$:.unshift File.join($top_srcdir, 'lib')
+load './lib/deltacloud_rack.rb'
 
-server_dir = ENV['API_FRONTEND'] == 'cimi' ? 'cimi' : 'deltacloud'
+Deltacloud::configure do |server|
+  server.root_url '/api'
+  server.version '0.5.0'
+  server.klass 'Deltacloud::API'
+end
 
-load File.join($top_srcdir, 'lib', server_dir, 'server.rb')
+if ENV['API_FRONTEND'] == 'cimi'
+  Deltacloud::configure do |server|
+    server.root_url '/cimi'
+    server.version '1.0.0'
+    server.klass 'CIMI::API'
+  end
+end
 
-run Sinatra::Application
+Deltacloud.require_frontend!
+
+class IndexEntrypoint < Sinatra::Base
+  get "/" do
+    redirect Deltacloud[:root_url], 301
+  end
+end
+
+run Rack::Builder.new {
+  use Rack::MatrixParams
+  use Rack::DriverSelect
+
+  run Rack::URLMap.new(
+    "/" => IndexEntrypoint.new,
+    Deltacloud[:root_url] => Deltacloud[:klass],
+    "/stylesheets" =>  Rack::Directory.new( "public/stylesheets" ),
+    "/javascripts" =>  Rack::Directory.new( "public/javascripts" )
+  )
+} if respond_to? :run
diff --git a/server/lib/deltacloud/base_driver/base_driver.rb b/server/lib/deltacloud/base_driver/base_driver.rb
deleted file mode 100644
index 01dd5e7..0000000
--- a/server/lib/deltacloud/base_driver/base_driver.rb
+++ /dev/null
@@ -1,250 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/base_driver/exceptions'
-
-module Deltacloud
-
-  class BaseDriver
-
-    include ExceptionHandler
-
-    STATE_MACHINE_OPTS = {
-      :all_states => [:start, :pending, :running, :stopping, :stopped, :finish],
-      :all_actions => [:create, :reboot, :stop, :start, :destroy]
-    }
-
-    def name
-      self.class.name.split('::').last.gsub('Driver', '').downcase
-    end
-
-    def self.exceptions(&block)
-      ExceptionHandler::exceptions(&block)
-    end
-
-    def self.define_hardware_profile(name,&block)
-      @hardware_profiles ||= []
-      hw_profile = @hardware_profiles.find{|e| e.name == name}
-      return if hw_profile
-      hw_profile = ::Deltacloud::HardwareProfile.new( name, &block )
-      @hardware_profiles << hw_profile
-      hw_params = hw_profile.params
-      unless hw_params.empty?
-        feature :instances, :hardware_profiles do
-          decl.operation(:create) { add_params(hw_params) }
-        end
-      end
-    end
-
-    def self.hardware_profiles
-      @hardware_profiles ||= []
-      @hardware_profiles
-    end
-
-    def hardware_profiles(credentials, opts = nil)
-      results = self.class.hardware_profiles
-      filter_hardware_profiles(results, opts)
-    end
-
-    def hardware_profile(credentials, name)
-      hardware_profiles(credentials, :id => name).first
-    end
-
-    def filter_hardware_profiles(profiles, opts)
-      if opts
-        if v = opts[:architecture]
-          profiles = profiles.select { |hwp| hwp.include?(:architecture, v) }
-        end
-        # As a request param, we call 'name' 'id'
-        if v = opts[:id]
-          profiles = profiles.select { |hwp| hwp.name == v }
-        end
-      end
-      profiles
-    end
-
-    def find_hardware_profile(credentials, name, image_id)
-      hwp = nil
-      if name
-        unless hwp = hardware_profiles(credentials, :id => name).first
-          raise BackendError.new(400, "bad-hardware-profile-name",
-            "Hardware profile '#{name}' does not exist", nil)
-        end
-      else
-        unless image = image(credentials, :id=>image_id)
-          raise BackendError.new(400, "bad-image-id",
-              "Image with ID '#{image_id}' does not exist", nil)
-        end
-        hwp = hardware_profiles(credentials,
-                                :architecture=>image.architecture).first
-      end
-      return hwp
-    end
-
-    def self.define_instance_states(&block)
-      machine = ::Deltacloud::StateMachine.new(STATE_MACHINE_OPTS, &block)
-      @instance_state_machine = machine
-    end
-
-    def self.instance_state_machine
-      @instance_state_machine
-    end
-
-    def instance_state_machine
-      self.class.instance_state_machine
-    end
-
-    def instance_actions_for(state)
-      actions = []
-      state_key = state.downcase.to_sym
-      states = instance_state_machine.states()
-      current_state = states.find{|e| e.name == state.underscore.to_sym }
-      if ( current_state )
-        actions = current_state.transitions.collect{|e|e.action}
-        actions.reject!{|e| e.nil?}
-      end
-      actions
-    end
-
-    ## Capabilities
-    # The rabbit dsl supports declaring a capability that is required
-    # in the backend driver for the call to succeed. A driver can
-    # provide a capability by implementing the method with the same
-    # name as the capability. Below is a list of the capabilities as
-    # the expected method signatures.
-    #
-    # Following the capability list are the resource member show
-    # methods. They each require that the corresponding collection
-    # method be defined
-    #
-    # TODO: standardize all of these to the same signature (credentials, opts)
-    #
-    # def realms(credentials, opts=nil)
-    #
-    # def images(credentials, ops)
-    #
-    # def instances(credentials, ops)
-    # def create_instance(credentials, image_id, opts)
-    # def start_instance(credentials, id)
-    # def stop_instance(credentials, id)
-    # def reboot_instance(credentials, id)
-    #
-    # def storage_volumes(credentials, ops)
-    #
-    # def storage_snapshots(credentials, ops)
-    #
-    # def buckets(credentials, opts = nil)
-    # def create_bucket(credentials, name, opts=nil)
-    # def delete_bucket(credentials, name, opts=nil)
-    #
-    # def blobs(credentials, opts = nil)
-    # def blob_data(credentials, bucket_id, blob_id, opts)
-    # def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
-    # def delete_blob(credentials, bucket_id, blob_id, opts=nil)
-    #
-    # def keys(credentials, opts)
-    # def create_key(credentials, opts)
-    # def destroy_key(credentials, opts)
-    #
-    # def firewalls(credentials, opts)
-    # def create_firewall(credentials, opts)
-    # def delete_firewall(credentials, opts)
-    # def create_firewall_rule(credentials, opts)
-    # def delete_firewall_rule(credentials, opts)
-    # def providers(credentials)
-    def realm(credentials, opts)
-      realms = realms(credentials, opts).first if has_capability?(:realms)
-    end
-
-    def image(credentials, opts)
-      images(credentials, opts).first if has_capability?(:images)
-    end
-
-    def instance(credentials, opts)
-      instances(credentials, opts).first if has_capability?(:instances)
-    end
-
-    def storage_volume(credentials, opts)
-      storage_volumes(credentials, opts).first if has_capability?(:storage_volumes)
-    end
-
-    def storage_snapshot(credentials, opts)
-      storage_snapshots(credentials, opts).first if has_capability?(:storage_snapshots)
-    end
-
-    def bucket(credentials, opts = {})
-      #list of objects within bucket
-      buckets(credentials, opts).first if has_capability?(:buckets)
-    end
-
-    def blob(credentials, opts = {})
-      blobs(credentials, opts).first if has_capability?(:blobs)
-    end
-
-    def key(credentials, opts=nil)
-      keys(credentials, opts).first if has_capability?(:keys)
-    end
-
-    def firewall(credentials, opts={})
-      firewalls(credentials, opts).first if has_capability?(:firewalls)
-    end
-
-    MEMBER_SHOW_METHODS =
-      [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key, :firewall ]
-
-    def has_capability?(capability)
-      if MEMBER_SHOW_METHODS.include?(capability.to_sym)
-        has_capability?(capability.to_s.pluralize)
-      else
-        respond_to?(capability)
-      end
-    end
-
-    def filter_on(collection, attribute, opts)
-      return collection if opts.nil?
-      return collection if opts[attribute].nil?
-      filter = opts[attribute]
-      if ( filter.is_a?( Array ) )
-        return collection.select{|e| filter.include?( e.send(attribute) ) }
-      else
-        return collection.select{|e| filter == e.send(attribute) }
-      end
-    end
-
-    def supported_collections
-      DEFAULT_COLLECTIONS
-    end
-
-    def has_collection?(collection)
-      supported_collections.include?(collection)
-    end
-
-    def catched_exceptions_list
-      { :error => [], :auth => [], :glob => [] }
-    end
-
-    def api_provider
-      Thread.current[:provider] || ENV['API_PROVIDER']
-    end
-
-    # Return an array of the providers statically configured
-    # in the driver's YAML file
-    def configured_providers
-      []
-    end
-  end
-
-end
diff --git a/server/lib/deltacloud/base_driver/exceptions.rb b/server/lib/deltacloud/base_driver/exceptions.rb
deleted file mode 100644
index a89b05f..0000000
--- a/server/lib/deltacloud/base_driver/exceptions.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-module Deltacloud
-  module ExceptionHandler
-
-    class DeltacloudException < StandardError
-
-      attr_accessor :code, :name, :message, :backtrace, :request
-
-      def initialize(code, name, message, backtrace, request=nil)
-        @code, @name, @message = code, name, message
-        @backtrace = backtrace
-        @request = request
-        self
-      end
-
-    end
-
-    class AuthenticationFailure < DeltacloudException
-      def initialize(e, message=nil)
-        message ||= e.message
-        super(401, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class UnknownMediaTypeError < DeltacloudException
-      def initialize(e, message=nil)
-        message ||= e.message
-        super(406, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class MethodNotAllowed < DeltacloudException
-      def initialize(e, message=nil)
-        message ||= e.message
-        super(405, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class ValidationFailure < DeltacloudException
-      def initialize(e, message=nil)
-        message ||= e.message
-        super(400, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class BackendError < DeltacloudException
-      def initialize(e, message=nil)
-        message ||= e.message
-        super(500, e.class.name, message, e.backtrace, message)
-      end
-    end
-
-    class ProviderError < DeltacloudException
-      def initialize(e, message)
-        message ||= e.message
-        super(502, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class ProviderTimeout < DeltacloudException
-      def initialize(e, message)
-        message ||= e.message
-        super(504, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class NotImplemented < DeltacloudException
-      def initialize(e, message)
-        message ||= e.message
-        super(501, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class ObjectNotFound < DeltacloudException
-      def initialize(e, message)
-        message ||= e.message
-        super(404, e.class.name, message, e.backtrace)
-      end
-    end
-
-    class NotSupported < DeltacloudException
-      def initialize(message)
-        super(501, self.class.name, message, self.backtrace)
-      end
-    end
-
-    class ExceptionDef
-      attr_accessor :status
-      attr_accessor :message
-      attr_reader   :conditions
-      attr_reader   :handler
-
-      def initialize(conditions, &block)
-        @conditions = conditions
-        instance_eval(&block) if block_given?
-      end
-
-      def status(code)
-        self.status = code
-      end
-
-      def message(message)
-        self.message = message
-      end
-
-      def exception(handler)
-        self.handler = handler
-      end
-
-      # Condition can be class or regexp
-      #
-      def match?(e)
-        @conditions.each do |c|
-          return true if c.class == Class && e.class == c
-          return true if c.class == Regexp && (e.class.name =~ c or e.message =~ c)
-        end
-        return false
-      end
-
-      def handler(e)
-        return @handler if @handler
-        case @status
-          when 401 then Deltacloud::ExceptionHandler::AuthenticationFailure.new(e, @message)
-          when 404 then Deltacloud::ExceptionHandler::ObjectNotFound.new(e, @message)
-          when 406 then Deltacloud::ExceptionHandler::UnknownMediaTypeError.new(e, @message)
-          when 405 then Deltacloud::ExceptionHandler::MethodNotAllowed.new(e, @message)
-          when 400 then Deltacloud::ExceptionHandler::ValidationFailure.new(e, @message)
-          when 500 then Deltacloud::ExceptionHandler::BackendError.new(e, @message)
-          when 501 then Deltacloud::ExceptionHandler::NotImplemented.new(e, @message)
-          when 502 then Deltacloud::ExceptionHandler::ProviderError.new(e, @message)
-          when 504 then Deltacloud::ExceptionHandler::ProviderTimeout.new(e, @message)
-        end
-      end
-
-    end
-
-    class Exceptions
-      attr_reader :exception_definitions
-
-      def initialize(&block)
-        @exception_definitions = []
-        instance_eval(&block) if block_given?
-        self
-      end
-
-      def on(*conditions, &block)
-        @exception_definitions << ExceptionDef::new(conditions, &block) if block_given?
-      end
-    end
-
-    def self.exceptions(&block)
-      @definitions = Exceptions.new(&block).exception_definitions if block_given?
-      @definitions
-    end
-
-    def safely(&block)
-      begin
-        block.call
-      rescue
-        report_method = $stderr.respond_to?(:err) ? :err : :puts
-        Deltacloud::ExceptionHandler::exceptions.each do |exdef|
-          if exdef.match?($!)
-            new_exception = exdef.handler($!)
-            m = new_exception.message.nil? ? $!.message : new_exception.message
-            $stderr.send(report_method, "#{[$!.class.to_s, m].join(':')}\n#{$!.backtrace[0..10].join("\n")}")
-            raise exdef.handler($!) unless new_exception.nil?
-          end
-        end
-        $stderr.send(report_method, "[NO HANDLED] #{[$!.class.to_s, $!.message].join(': ')}\n#{$!.backtrace.join("\n")}")
-        raise Deltacloud::ExceptionHandler::BackendError.new($!, "Unhandled exception or status code (#{$!.message})")
-      end
-    end
-
-  end
-
-end
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
deleted file mode 100644
index 37e5ef0..0000000
--- a/server/lib/deltacloud/base_driver/features.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/validation'
-
-# Add advertising of optional features to the base driver
-module Deltacloud
-
-  class FeatureError < StandardError; end
-  class DuplicateFeatureDeclError < FeatureError; end
-  class UndeclaredFeatureError < FeatureError; end
-
-  class BaseDriver
-
-    # An operation on a collection like cretae or show. Features
-    # can add parameters to operations
-    class Operation
-      attr_reader :name
-
-      include Deltacloud::Validation
-
-      def initialize(name, &block)
-        @name = name
-        @params = {}
-        instance_eval &block
-      end
-    end
-
-    # The declaration of a feature, defines what operations
-    # are modified by it
-    class FeatureDecl
-      attr_reader :name, :operations
-
-      def initialize(name, &block)
-        @name = name
-        @operations = []
-        instance_eval &block
-      end
-
-      def description(text=nil)
-        @description = text if text
-        @description
-      end
-
-      # Add/modify an operation or look up an existing one. If +block+ is
-      # provided, create a new operation if none exists with name
-      # +name+. Evaluate the +block+ against this instance. If no +block+
-      # is provided, look up the operation with name +name+
-      def operation(name, &block)
-        op = @operations.find { |op| op.name == name }
-        if block_given?
-          if op.nil?
-            op = Operation.new(name, &block)
-            @operations << op
-          else
-            op.instance_eval(&block)
-          end
-        end
-        op
-      end
-    end
-
-    # A specific feature enabled by a driver (see +feature+)
-    class Feature
-      attr_reader :decl, :constraints
-
-      def initialize(decl, &block)
-        @decl = decl
-        @constraints = {}
-        instance_eval &block if block_given?
-      end
-
-      def name
-        decl.name
-      end
-
-      def operations
-        decl.operations
-      end
-
-      def description
-        decl.description
-      end
-
-      def constraint(name, value)
-        @constraints[name] = value
-      end
-    end
-
-    def self.feature_decls
-      @@feature_decls ||= {}
-    end
-
-    def self.feature_decl_for(collection, name)
-      decls = feature_decls[collection]
-      if decls
-        decls.find { |dcl| dcl.name == name }
-      else
-        nil
-      end
-    end
-
-    # Declare a new feature
-    def self.declare_feature(collection, name, &block)
-      feature_decls[collection] ||= []
-      raise DuplicateFeatureDeclError if feature_decl_for(collection, name)
-      feature_decls[collection] << FeatureDecl.new(name, &block)
-    end
-
-    def self.features
-      @features ||= {}
-    end
-
-    # Declare in a driver that it supports a specific feature
-    #
-    # The same feature can be declared multiple times in a driver, so that
-    # it can be changed successively by passing in different blocks.
-    def self.feature(collection, name, &block)
-      features[collection] ||= []
-      if f = features[collection].find { |f| f.name == name }
-        f.instance_eval(&block) if block_given?
-        return f
-      end
-      unless decl = feature_decl_for(collection, name)
-        raise UndeclaredFeatureError, "No feature #{name} for #{collection}"
-      end
-      features[collection] << Feature.new(decl, &block)
-    end
-
-    def features(collection)
-      self.class.features[collection] || []
-    end
-
-    def features_for_operation(collection, operation)
-      features(collection).select do |f|
-        f.operations.detect { |o| o.name == operation }
-      end
-    end
-
-    #
-    # Declaration of optional features
-    #
-    declare_feature :images,  :owner_id do
-      description "Filter images using owner id"
-      operation :index do
-        param :owner_id,  :string,  :optional,  [],  "Owner ID"
-      end
-    end
-
-    declare_feature :images,  :user_name do
-      description "Allow specifying user name for created image"
-      operation :create do
-        param :name,  :string,  :optional,  [],  "Image name"
-      end
-    end
-
-    declare_feature :images,  :user_description do
-      description "Allow specifying user description for created image"
-      operation :create do
-        param :description, :string,  :optional,  [],  "Image description"
-      end
-    end
-
-    declare_feature :instances, :user_name do
-      description "Accept a user-defined name on instance creation"
-      operation :create do
-        param :name, :string, :optional, [], "The user-defined name"
-      end
-    end
-
-    declare_feature :instances, :user_data do
-      description "Make user-defined data available on a special webserver"
-      operation :create do
-        param :user_data, :string, :optional, [],
-        "Base64 encoded user data will be published to internal webserver"
-      end
-    end
-
-    declare_feature :instances, :user_iso do
-      description "Make user-defined ISO available inside instance"
-      operation :create do
-        param :user_iso, :string, :optional, [],
-        "Base64 encoded gzipped ISO file will be accessible as CD-ROM drive in instance"
-      end
-    end
-
-    declare_feature :instances, :user_files do
-      description "Accept up to 5 files to be placed into the instance before launch."
-      operation :create do
-        1.upto(5) do |i|
-          param :"path#{i}", :string, :optional, [],
-          "Path where to place the #{i.ordinalize} file, up to 255 characters"
-          param :"content#{i}", :string, :optional, nil,
-          "Contents for the #{i.ordinalize} file, up to 10 kB, Base64 encoded"
-        end
-      end
-    end
-
-    declare_feature :instances, :firewalls do
-      description "Put instance in one or more firewalls (security groups) on launch"
-      operation :create do
-        param :firewalls, :array, :optional, nil, "Array of firewall ID strings"
-        "Array of firewall (security group) id"
-      end
-    end
-
-    declare_feature :instances, :authentication_key do
-      operation :create do
-        param :keyname, :string,  :optional, [], "Key authentification method"
-      end
-      operation :show do
-      end
-    end
-
-    declare_feature :instances, :authentication_password do
-      operation :create do
-        param :password, :string, :optional
-      end
-    end
-
-    declare_feature :instances, :hardware_profiles do
-      description "Size instances according to changes to a hardware profile"
-      # The parameters are filled in from the hardware profiles
-    end
-
-    declare_feature :buckets, :bucket_location do
-      description "Take extra location parameter for Bucket creation (e.g. S3, 'eu' or 'us-west-1')"
-      operation :create do
-        param :location, :string, :optional
-      end
-    end
-
-    declare_feature :instances, :register_to_load_balancer do
-      description "Register instance to load balancer"
-      operation :create do
-        param :load_balancer_id, :string, :optional
-      end
-    end
-
-    declare_feature :instances, :instance_count do
-      description "Number of instances to be launch with at once"
-      operation :create do
-        param :instance_count,  :string,  :optional
-      end
-    end
-
-    declare_feature :instances, :attach_snapshot do
-      description "Attach an snapshot to instance on create"
-      operation :create do
-        param :snapshot_id,  :string,  :optional
-        param :device_name,  :string,  :optional
-      end
-    end
-
-    declare_feature :instances, :sandboxing do
-      description "Allow lanuching sandbox images"
-      operation :create do
-        param :sandbox, :string,  :optional
-      end
-    end
-
-  end
-end
diff --git a/server/lib/deltacloud/collections.rb b/server/lib/deltacloud/collections.rb
new file mode 100644
index 0000000..2363887
--- /dev/null
+++ b/server/lib/deltacloud/collections.rb
@@ -0,0 +1,54 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+
+  def self.collection_names
+    @collections.map { |c| c.collection_name }
+  end
+
+  def self.collections
+    @collections ||= []
+  end
+
+  module Collections
+
+    def self.collection(name)
+      Deltacloud.collections.find { |c| c.collection_name == name }
+    end
+
+    def self.deltacloud_modules
+      @deltacloud_modules ||= []
+    end
+
+    Dir[File.join(File::dirname(__FILE__), "collections", "*.rb")].each do |collection|
+      require collection
+      base_collection_name = File.basename(collection).gsub('.rb', '')
+      deltacloud_module_class = Deltacloud::Collections.const_get(base_collection_name.camelize)
+      deltacloud_modules << deltacloud_module_class
+      deltacloud_module_class.collections.each do |c|
+        Deltacloud.collections << c
+      end unless deltacloud_module_class.collections.nil?
+    end
+
+    def self.included(klass)
+      klass.class_eval do
+        Deltacloud::Collections.deltacloud_modules.each { |c| use c }
+      end
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/addresses.rb b/server/lib/deltacloud/collections/addresses.rb
new file mode 100644
index 0000000..b97d170
--- /dev/null
+++ b/server/lib/deltacloud/collections/addresses.rb
@@ -0,0 +1,83 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Addresses < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :addresses do
+      description "Pool of IP addresses allocated in cloud provider"
+
+      standard_index_operation
+      standard_show_operation
+
+      operation :create, :with_capability => :create_address do
+        description "Acquire a new IP address for use with your account."
+        control do
+          @address = driver.create_address(credentials, {})
+          status 201    # Created
+          response['Location'] = address_url(@address.id)
+          respond_to do |format|
+            format.xml  { haml :"addresses/show", :ugly => true }
+            format.html { haml :"addresses/_address", :layout => false }
+            format.json { convert_to_json(:address, @address) }
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_address do
+        control do
+          driver.destroy_address(credentials, { :id => params[:id]})
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(addresses_url) }
+          end
+        end
+      end
+
+      action :associate, :with_capability => :associate_address do
+        description "Associate an IP address to an instance"
+        param :instance_id, :string, :required
+        control do
+          driver.associate_address(credentials, { :id => params[:id], :instance_id => params[:instance_id]})
+          status 202   # Accepted
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(address_url(params[:id])) }
+          end
+        end
+      end
+
+      action :disassociate, :with_capability => :associate_address do
+        description "Disassociate an IP address from an instance"
+        control do
+          driver.disassociate_address(credentials, { :id => params[:id] })
+          status 202   # Accepted
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(address_url(params[:id])) }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/buckets.rb b/server/lib/deltacloud/collections/buckets.rb
new file mode 100644
index 0000000..044bd6a
--- /dev/null
+++ b/server/lib/deltacloud/collections/buckets.rb
@@ -0,0 +1,215 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Buckets < Base
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    collection :buckets do
+
+      collection :blobs, :with_id => :blob_id, :no_member => true do
+
+        operation :show, :with_capability => :blob do
+          control do
+            @blob = driver.blob(credentials, { :id => params[:blob_id], 'bucket' => params[:id]} )
+            if @blob
+              respond_to do |format|
+                format.xml { haml :"blobs/show" }
+                format.html { haml :"blobs/show" }
+                format.json { convert_to_json(:blob, @blob) }
+              end
+            else
+              report_error(404)
+            end
+          end
+
+        end
+
+        operation :create, :with_capability => :create_blob do
+          description "Create new blob"
+          param :blob_id,  :string,  :required
+          param :blob_data, :hash, :required
+          control do
+            bucket_id = params[:id]
+            blob_id = params['blob_id']
+            blob_data = params['blob_data']
+            user_meta = {}
+            #metadata from params (i.e., passed by http form post, e.g. browser)
+            max = params[:meta_params]
+            if(max)
+              (1..max.to_i).each do |i|
+                key = params[:"meta_name#{i}"]
+                key = "HTTP_X_Deltacloud_Blobmeta_#{key}"
+                value = params[:"meta_value#{i}"]
+                user_meta[key] = value
+              end
+            end
+            @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
+            respond_to do |format|
+              format.xml { haml :"blobs/show" }
+              format.html { haml :"blobs/show"}
+              format.json {convert_to_json(:blob, @blob)}
+            end
+          end
+        end
+
+        operation :destroy, :with_capability => :delete_blob do
+          control do
+            bucket_id = params[:id]
+            blob_id = params[:blob_id]
+            driver.delete_blob(credentials, bucket_id, blob_id)
+            status 204
+            respond_to do |format|
+              format.xml
+              format.json
+              format.html { redirect(bucket_url(bucket_id)) }
+            end
+          end
+        end
+
+        action :stream, :http_method => :put, :with_capability => :create_blob do
+          description "Stream new blob data into the blob"
+          control do
+            if(env["BLOB_SUCCESS"]) #ie got a 200ok after putting blob
+              content_type = env["CONTENT_TYPE"]
+              content_type ||=  ""
+              @blob = driver.blob(credentials, {:id => params[:blob],
+                                                'bucket' => params[:bucket]})
+              respond_to do |format|
+                format.xml { haml :"blobs/show" }
+                format.html { haml :"blobs/show" }
+                format.json { convert_to_json(:blob, @blob) }
+              end
+            elsif(env["BLOB_FAIL"])
+              report_error(500) #OK?
+            else # small blobs - < 112kb dont hit the streaming monkey patch - use 'normal' create_blob
+              # also, if running under webrick don't hit the streaming patch (Thin specific)
+              bucket_id = params[:bucket]
+              blob_id = params[:blob]
+              temp_file = Tempfile.new("temp_blob_file")
+              temp_file.write(env['rack.input'].read)
+              temp_file.flush
+              content_type = env['CONTENT_TYPE'] || ""
+              blob_data = {:tempfile => temp_file, :type => content_type}
+              user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
+              @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
+              temp_file.delete
+              respond_to do |format|
+                format.xml { haml :"blobs/show" }
+                format.html { haml :"blobs/show" }
+                format.json { convert_to_json(:blob, @blob) }
+              end
+            end
+          end
+        end
+
+        action :metadata, :http_method => :head, :with_capability => :blob_metadata do
+          control do
+            @blob_id = params[:blob]
+            @blob_metadata = driver.blob_metadata(credentials, {:id => params[:blob], 'bucket' => params[:bucket]})
+            if @blob_metadata
+              @blob_metadata.each do |k,v|
+                headers["X-Deltacloud-Blobmeta-#{k}"] = v
+              end
+              status 204
+              respond_to do |format|
+                format.xml
+                format.json
+              end
+            else
+              report_error(404)
+            end
+          end
+        end
+
+        action :update, :http_method => :post, :with_capability => :update_blob_metadata do
+          control do
+            meta_hash = BlobHelper::extract_blob_metadata_hash(request.env)
+            success = driver.update_blob_metadata(credentials, {'bucket'=>params[:bucket], :id =>params[:blob], 'meta_hash' => meta_hash})
+            if(success)
+              meta_hash.each do |k,v|
+                headers["X-Deltacloud-Blobmeta-#{k}"] = v
+              end
+              status 204
+              respond_to do |format|
+                format.xml
+                format.json
+              end
+            else
+              report_error(404) #FIXME is this the right error code?
+            end
+          end
+        end
+
+        action :content, :http_method => :get, :with_capability => :blob do
+          description "Download blob content"
+          control do
+            @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
+            if @blob
+              params['content_length'] = @blob.content_length
+              params['content_type'] = @blob.content_type
+              params['content_disposition'] = "attachment; filename=#{@blob.id}"
+              BlobStream.call(env, credentials, params)
+            else
+              report_error(404)
+            end
+          end
+        end
+
+      end
+
+      get route_for('/buckets/new') do
+        respond_to do |format|
+          format.html { haml :"buckets/new" }
+        end
+      end
+
+      standard_show_operation
+      standard_index_operation
+
+      operation :create, :with_capability => :create_bucket do
+        param :name,      :string,    :required
+        control do
+          @bucket = driver.create_bucket(credentials, params[:name], params)
+          status 201
+          response['Location'] = bucket_url(@bucket.id)
+          respond_to do |format|
+            format.xml  { haml :"buckets/show" }
+            format.json { convert_to_json(:bucket, @bucket) }
+            format.html do
+              redirect bucket_url(@bucket.id) if @bucket and @bucket.id
+              redirect buckets_url
+            end
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :delete_bucket do
+        control do
+          driver.delete_bucket(credentials, params[:id], params)
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html {  redirect(buckets_url) }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/drivers.rb b/server/lib/deltacloud/collections/drivers.rb
new file mode 100644
index 0000000..41f324a
--- /dev/null
+++ b/server/lib/deltacloud/collections/drivers.rb
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Drivers < Base
+
+    collection :drivers do
+
+      operation :index do
+        control do
+          @drivers = Deltacloud::Drivers.driver_config
+          respond_to do |format|
+            format.xml { haml :"drivers/index" }
+            format.json { @drivers.to_json }
+            format.html { haml :"drivers/index" }
+          end 
+        end
+      end
+
+      operation :show do
+        control do
+          @name = params[:id].to_sym
+          if driver_symbol == @name
+            @providers = driver.providers(credentials)  if driver.respond_to? :providers
+          end
+          @driver = Deltacloud::Drivers.driver_config[@name]
+          halt 404 unless @driver
+          respond_to do |format|
+            format.xml { haml :"drivers/show" }
+            format.json { @driver.to_json }
+            format.html { haml :"drivers/show" }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/firewalls.rb b/server/lib/deltacloud/collections/firewalls.rb
new file mode 100644
index 0000000..0a4242a
--- /dev/null
+++ b/server/lib/deltacloud/collections/firewalls.rb
@@ -0,0 +1,116 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Firewalls < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    get route_for('/firewalls/:id/new_rule') do
+      @firewall_name = params[:id]
+      respond_to do |format|
+        format.html {haml :"firewalls/new_rule" }
+      end
+    end
+
+    new_route_for :firewalls
+
+    collection :firewalls do
+      description "Allow user to define firewall rules for an instance (ec2 security groups) eg expose ssh access [port 22, tcp]."
+
+      collection :rules, :with_id => :rule_id, :no_member => true do
+
+        operation :destroy, :with_capability => :delete_firewall_rule do
+          control do
+            opts = {}
+            opts[:firewall] = params[:id]
+            opts[:rule_id] = params[:rule_id]
+            driver.delete_firewall_rule(credentials, opts)
+            status 204
+            respond_to do |format|
+              format.xml
+              format.json
+              format.html {redirect firewall_url(params[:id])}
+            end
+          end
+        end
+
+      end
+
+      standard_show_operation
+      standard_index_operation
+
+      operation :create, :with_capability => :create_firewall do
+        param :name,          :string,    :required
+        param :description,   :string,    :required
+        control do
+          @firewall = driver.create_firewall(credentials, params )
+          status 201  # Created
+          response['Location'] = firewall_url(@firewall.id)
+          respond_to do |format|
+            format.xml  { haml :"firewalls/show" }
+            format.html { haml :"firewalls/show" }
+            format.json { convert_to_json(:firewall, @firewall) }
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :delete_firewall do
+        control do
+          driver.delete_firewall(credentials, params)
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html {  redirect(firewalls_url) }
+          end
+        end
+      end
+
+      action :rules, :with_capability => :create_firewall_rule do
+        param :protocol,  :required, :string, ['tcp','udp','icmp'], "Transport layer protocol for the rule"
+        param :port_from, :required, :string, [], "Start of port range for the rule"
+        param :port_to,   :required, :string, [], "End of port range for the rule"
+        control do
+          #source IPs from params
+          addresses =  params.inject([]){|result,current| result << current.last unless current.grep(/^ip[-_]address/i).empty?; result}
+          #source groups from params
+          groups = {}
+          max_groups  = params.select{|k,v| k=~/^group/}.size/2
+          for i in (1..max_groups) do
+            groups.merge!({params["group#{i}"]=>params["group#{i}owner"]})
+          end
+          params['addresses'] = addresses
+          params['groups'] = groups
+          if addresses.empty? && groups.empty?
+            raise Deltacloud::ExceptionHandler::ValidationFailure.new(
+              StandardError.new("No sources. Specify at least one source ip_address or group")
+            )
+          end
+          driver.create_firewall_rule(credentials, params)
+          @firewall = driver.firewall(credentials, {:id => params[:id]})
+          status 201
+          respond_to do |format|
+            format.xml  { haml :"firewalls/show" }
+            format.html { haml :"firewalls/show" }
+            format.json { convert_to_json(:firewall, @firewall) }
+          end
+        end
+      end
+
+    end
+  end
+end
diff --git a/server/lib/deltacloud/collections/hardware_profiles.rb b/server/lib/deltacloud/collections/hardware_profiles.rb
new file mode 100644
index 0000000..ff01d4a
--- /dev/null
+++ b/server/lib/deltacloud/collections/hardware_profiles.rb
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class HardwareProfiles < Base
+
+    collection :hardware_profiles do
+
+      standard_index_operation
+      standard_show_operation
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/images.rb b/server/lib/deltacloud/collections/images.rb
new file mode 100644
index 0000000..c8b3e08
--- /dev/null
+++ b/server/lib/deltacloud/collections/images.rb
@@ -0,0 +1,70 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Images < Base
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    new_route_for :images do
+      @instance = Instance.new( :id => params[:instance_id] )
+      status 404 unless @instance
+    end
+
+    collection :images do
+      description "Within a cloud provider a realm represents a boundary containing resources"
+
+      operation :index, :with_capability => :images do
+        param :architecture,  :string,  :optional
+        control { filter_all(:images) }
+      end
+
+      operation :show, :with_capability => :image do
+        control { show(:image) }
+      end
+
+      operation :create, :with_capability => :create_image do
+        param :instance_id, :string, :required
+        control do
+          @image = driver.create_image(credentials, {
+            :id => params[:instance_id],
+            :name => params[:name],
+            :description => params[:description]
+          })
+          status 201  # Created
+          response['Location'] = image_url(@image.id)
+          respond_to do |format|
+            format.xml  { haml :"images/show" }
+            format.json { xml_to_json('images/show') }
+            format.html { haml :"images/show" }
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_image do
+        control do
+          driver.destroy_image(credentials, params[:id])
+          respond_to do |format|
+            format.xml { status 204 }
+            format.json { status 204 }
+            format.html { redirect(images_url) }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/instance_states.rb b/server/lib/deltacloud/collections/instance_states.rb
new file mode 100644
index 0000000..56c1561
--- /dev/null
+++ b/server/lib/deltacloud/collections/instance_states.rb
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class InstanceStates < Base
+
+    collection :instance_states do
+      operation :index do
+        control do
+          @machine = driver.instance_state_machine
+          respond_to do |format|
+            format.xml { haml :'instance_states/show', :layout => false }
+            format.json do
+              out = []
+              @machine.states.each do |state|
+                transitions = state.transitions.collect do |t|
+                  t.automatically? ? {:to => t.destination, :auto => 'true'} : {:to => t.destination, :action => t.action}
+                end
+                out << { :name => state, :transitions => transitions }
+              end
+              out.to_json
+            end
+            format.html { haml :'instance_states/show'}
+            format.gv { erb :"instance_states/show" }
+            format.png do
+              # Trick respond_to into looking up the right template for the
+              # graphviz file
+              gv = erb(:"instance_states/show")
+              png =  ''
+              cmd = 'dot -Kdot -Gpad="0.2,0.2" -Gsize="5.0,8.0" -Gdpi="180" -Tpng'
+              Open3.popen3( cmd ) do |stdin, stdout, stderr|
+                stdin.write( gv )
+                stdin.close()
+                png = stdout.read
+              end
+              content_type 'image/png'
+              png
+            end
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/instances.rb b/server/lib/deltacloud/collections/instances.rb
new file mode 100644
index 0000000..5202149
--- /dev/null
+++ b/server/lib/deltacloud/collections/instances.rb
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Instances < Base
+
+    include Deltacloud::InstanceFeatures
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    new_route_for(:instances) do
+      @instance = Instance.new( { :id=>params[:id], :image_id=>params[:image_id] } )
+      @image   = Image.new( :id => params[:image_id] )
+      @hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
+      @realms = [Realm.new(:id => params[:realm_id])] if params[:realm_id]
+      @realms ||= driver.realms(credentials)
+    end
+
+    collection :instances do
+
+      standard_show_operation
+      standard_index_operation
+
+      operation :create, :with_capability => :create_instance do
+        param :image_id,     :string, :required
+        param :realm_id,     :string, :optional
+        param :hwp_id,       :string, :optional
+        control do
+          @instance = driver.create_instance(credentials, params[:image_id], params)
+          if @instance.kind_of? Array
+            @elements = @instance
+            action_handler = "index"
+          else
+            response['Location'] = instance_url(@instance.id)
+            action_handler = "show"
+          end
+          status 201  # Created
+          respond_to do |format|
+            format.xml  { haml :"instances/#{action_handler}" }
+            format.json { xml_to_json("instances/#{action_handler}") }
+            format.html do
+              if @elements
+                haml :"instances/index"
+              elsif @instance and @instance.id
+                response['Location'] = instance_url(@instance.id)
+                haml :"instances/show"
+              else
+                redirect instances_url
+              end
+            end
+          end
+        end
+      end
+
+      action :reboot, :with_capability => :reboot_instance do
+        description "Reboot a running instance."
+        control { instance_action(:reboot) }
+      end
+
+      action :start, :with_capability => :start_instance do
+        description "Start an instance."
+        control { instance_action(:start) }
+      end
+
+      action :stop, :with_capability => :stop_instance do
+        description "Stop a running instance."
+        control { instance_action(:stop) }
+      end
+
+      operation :destroy, :with_capability => :destroy_instance do
+        control { instance_action(:destroy) }
+      end
+
+      action :run, :with_capability => :run_instance do
+        param :id,          :string,  :required
+        param :cmd,         :string,  :required, [], "Shell command to run on instance"
+        param :private_key, :string,  :optional, [], "Private key in PEM format for authentication"
+        param :password,    :string,  :optional, [], "Password used for authentication"
+        control do
+          @output = driver.run_on_instance(credentials, params)
+          respond_to do |format|
+            format.xml { haml :"instances/run" }
+            format.html { haml :"instances/run" }
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/keys.rb b/server/lib/deltacloud/collections/keys.rb
new file mode 100644
index 0000000..55d0fa8
--- /dev/null
+++ b/server/lib/deltacloud/collections/keys.rb
@@ -0,0 +1,61 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Keys < Base
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    get route_for('/keys/new') do
+      respond_to do |format|
+        format.html { haml :"keys/new" }
+      end
+    end
+
+    collection :keys do
+
+      standard_show_operation
+      standard_index_operation
+
+      operation :create, :with_capability => :create_key do
+        param :name,  :string,  :required
+        control do
+          @key = driver.create_key(credentials, { :key_name => params[:name] })
+          status 201
+          response['Location'] = key_url(@key.id)
+          respond_to do |format|
+            format.xml  { haml :"keys/show", :ugly => true }
+            format.html { haml :"keys/show" }
+            format.json { convert_to_json(:key, @key)}
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_key do
+        control do
+          driver.destroy_key(credentials, { :id => params[:id]})
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(keys_url) }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/load_balancers.rb b/server/lib/deltacloud/collections/load_balancers.rb
new file mode 100644
index 0000000..d093ead
--- /dev/null
+++ b/server/lib/deltacloud/collections/load_balancers.rb
@@ -0,0 +1,85 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class LoadBalancers < Base
+    check_capability :for => lambda { |m| driver.has_capability? m }
+
+    collection :load_balancers do
+      description "Load balancers are used distribute workload across multiple instances"
+
+      standard_index_operation
+      standard_show_operation
+
+      operation :create do
+        param :name,  :string,  :required
+        param :realm_id,  :string,  :required
+        param :listener_protocol,  :string,  :required, ['HTTP', 'TCP']
+        param :listener_balancer_port,  :string,  :required
+        param :listener_instance_port,  :string,  :required
+        control do
+          @load_balancer = driver.create_load_balancer(credentials, params)
+          status 201  # Created
+          response['Location'] = load_balancer_url(@instance.id)
+          respond_to do |format|
+            format.xml  { haml :"load_balancers/show" }
+            format.json { convert_to_json(:load_balancer, @load_balancer) }
+            format.html { haml :"load_balancers/show" }
+          end
+        end
+      end
+
+      action :register do
+        param :instance_id, :string,  :required
+        control do
+          driver.lb_register_instance(credentials, params)
+          @load_balancer = driver.load_balancer(credential, params[:id])
+          respond_to do |format|
+            format.xml { haml :'load_balancers/show' }
+            format.json ( xml_to_json('load_balancers/show'))
+            format.html { haml :'load_balancers/show' }
+          end
+        end
+      end
+
+      action :unregister do
+        param :instance_id, :string,  :required
+        control do
+          driver.lb_unregister_instance(credentials, params)
+          @load_balancer = driver.load_balancer(credential, params[:id])
+          respond_to do |format|
+            format.xml { haml :'load_balancers/show' }
+            format.json ( xml_to_json('load_balancers/show'))
+            format.html { haml :'load_balancers/show' }
+          end
+        end
+      end
+
+      operation :destroy do
+        control do
+          driver.destroy_load_balancer(credentials, params[:id])
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(load_balancers_url) }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/realms.rb b/server/lib/deltacloud/collections/realms.rb
new file mode 100644
index 0000000..3f21625
--- /dev/null
+++ b/server/lib/deltacloud/collections/realms.rb
@@ -0,0 +1,27 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class Realms < Base
+
+    collection :realms do
+      description "Within a cloud provider a realm represents a boundary containing resources"
+
+      standard_index_operation
+      standard_show_operation
+
+    end
+  end
+end
diff --git a/server/lib/deltacloud/collections/storage_snapshots.rb b/server/lib/deltacloud/collections/storage_snapshots.rb
new file mode 100644
index 0000000..b468614
--- /dev/null
+++ b/server/lib/deltacloud/collections/storage_snapshots.rb
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class StorageSnapshots < Base
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    new_route_for(:storage_snapshots)
+
+    collection :storage_snapshots do
+      standard_index_operation
+      standard_show_operation
+
+      operation :create, :with_capability => :create_storage_snapshot do
+        param :volume_id, :string,  :required
+        control do
+          @storage_snapshot = driver.create_storage_snapshot(credentials, params)
+          status 201  # Created
+          response['Location'] = storage_snapshot_url(@storage_snapshot.id)
+          show(:storage_snapshot)
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_storage_snapshot do
+        control do
+          driver.destroy_storage_snapshot(credentials, params)
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(storage_snapshots_url) }
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/collections/storage_volumes.rb b/server/lib/deltacloud/collections/storage_volumes.rb
new file mode 100644
index 0000000..9cdcd66
--- /dev/null
+++ b/server/lib/deltacloud/collections/storage_volumes.rb
@@ -0,0 +1,99 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Collections
+  class StorageVolumes < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    check_features :for => lambda { |c, f| driver.class.has_feature?(c, f) }
+
+    new_route_for(:storage_volumes)
+
+    get route_for("/storage_volumes/:id/attach_instance") do
+      @instances = driver.instances(credentials)
+      respond_to do |format|
+        format.html{ haml :"storage_volumes/attach"}
+      end
+    end
+
+    collection :storage_volumes do
+
+      standard_index_operation
+      standard_show_operation
+
+      operation :show, :with_capability => :storage_volume do
+        control { show(:storage_volume) }
+      end
+
+      operation :create do
+        param :snapshot_id, :string,  :optional
+        param :capacity,    :string,  :optional
+        param :realm_id,    :string,  :optional
+        control do
+          @storage_volume = driver.create_storage_volume(credentials, params)
+          status 201
+          response['Location'] = storage_volume_url(@storage_volume.id)
+          respond_to do |format|
+            format.xml  { haml :"storage_volumes/show" }
+            format.html { haml :"storage_volumes/show" }
+            format.json { convert_to_json(:storage_volume, @storage_volume) }
+          end
+        end
+      end
+
+      action :attach, :with_capability => :attach_storage_volume do
+        param :instance_id,:string,  :required
+        param :device,     :string,  :required
+        control do
+          @storage_volume = driver.attach_storage_volume(credentials, params)
+          status 202
+          respond_to do |format|
+            format.html { redirect(storage_volume_url(params[:id]))}
+            format.xml  { haml :"storage_volumes/show" }
+            format.json { convert_to_json(:storage_volume, @storage_volume) }
+          end
+        end
+      end
+
+      action :detach, :with_capability => :detach_storage_volume do
+        control do
+          volume = driver.storage_volume(credentials, :id => params[:id])
+          @storage_volume =  driver.detach_storage_volume(credentials, :id => volume.id, 
+                                                          :instance_id => volume.instance_id,
+                                                          :device => volume.device)
+          status 202
+          respond_to do |format|
+            format.html { redirect(storage_volume_url(params[:id]))}
+            format.xml  { haml :"storage_volumes/show" }
+            format.json { convert_to_json(:storage_volume, @storage_volume) }
+          end
+        end
+      end
+
+      operation :destroy, :with_capability => :destroy_storage_volume do
+        control do
+          driver.destroy_storage_volume(credentials, params)
+          status 204
+          respond_to do |format|
+            format.xml
+            format.json
+            format.html { redirect(storage_volumes_url) }
+          end
+        end
+      end
+
+    end
+  end
+end
diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb
new file mode 100644
index 0000000..5fb1a79
--- /dev/null
+++ b/server/lib/deltacloud/drivers/base_driver.rb
@@ -0,0 +1,265 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+
+  class BaseDriver
+
+    include ExceptionHandler
+
+    def self.driver_name
+      name.split('::').last.gsub('Driver', '').downcase
+    end
+
+    def self.features
+      @features ||= []
+    end
+
+    def self.features_for(entity)
+      features.inject([]) do |result, item|
+        result << item[entity] if item.has_key? entity
+        result
+      end
+    end
+
+    def self.feature(collection, feature_name)
+      return if has_feature?(collection, feature_name)
+      features << { collection => feature_name }
+    end
+
+    def self.has_feature?(collection, feature_name)
+      features.any? { |f| (f.values.first == feature_name) && (f.keys.first == collection) }
+    end
+
+    def name
+      self.class.name.split('::').last.gsub('Driver', '').downcase
+    end
+
+    def self.exceptions(&block)
+      ExceptionHandler::exceptions(&block)
+    end
+
+    def self.define_hardware_profile(name,&block)
+      @hardware_profiles ||= []
+      hw_profile = @hardware_profiles.find{|e| e.name == name}
+      return if hw_profile
+      hw_profile = ::Deltacloud::HardwareProfile.new( name, &block )
+      @hardware_profiles << hw_profile
+      hw_params = hw_profile.params
+      # FIXME: Features
+      #unless hw_params.empty?
+      #  feature :instances, :hardware_profiles do
+      #    decl.operation(:create) { add_params(hw_params) }
+      #  end
+      #end
+    end
+
+    def self.hardware_profiles
+      @hardware_profiles ||= []
+      @hardware_profiles
+    end
+
+    def hardware_profiles(credentials, opts = nil)
+      results = self.class.hardware_profiles
+      filter_hardware_profiles(results, opts)
+    end
+
+    def hardware_profile(credentials, name)
+      name = name[:id] if name.kind_of? Hash
+      hardware_profiles(credentials, :id => name).first
+    end
+
+    def filter_hardware_profiles(profiles, opts)
+      if opts
+        if v = opts[:architecture]
+          profiles = profiles.select { |hwp| hwp.include?(:architecture, v) }
+        end
+        # As a request param, we call 'name' 'id'
+        if v = opts[:id]
+          profiles = profiles.select { |hwp| hwp.name == v }
+        end
+      end
+      profiles
+    end
+
+    def find_hardware_profile(credentials, name, image_id)
+      hwp = nil
+      if name
+        unless hwp = hardware_profiles(credentials, :id => name).first
+          raise BackendError.new(400, "bad-hardware-profile-name",
+            "Hardware profile '#{name}' does not exist", nil)
+        end
+      else
+        unless image = image(credentials, :id=>image_id)
+          raise BackendError.new(400, "bad-image-id",
+              "Image with ID '#{image_id}' does not exist", nil)
+        end
+        hwp = hardware_profiles(credentials,
+                                :architecture=>image.architecture).first
+      end
+      return hwp
+    end
+
+    def self.define_instance_states(&block)
+      machine = ::Deltacloud::StateMachine.new(&block)
+      @instance_state_machine = machine
+    end
+
+    def self.instance_state_machine
+      @instance_state_machine
+    end
+
+    def instance_state_machine
+      self.class.instance_state_machine
+    end
+
+    def instance_actions_for(state)
+      actions = []
+      state_key = state.downcase.to_sym
+      states = instance_state_machine.states()
+      current_state = states.find{|e| e.name == state.underscore.to_sym }
+      if ( current_state )
+        actions = current_state.transitions.collect{|e|e.action}
+        actions.reject!{|e| e.nil?}
+      end
+      actions
+    end
+
+    def has_capability?(method)
+      (self.class.instance_methods - self.class.superclass.methods).include? method
+    end
+
+    ## Capabilities
+    # The rabbit dsl supports declaring a capability that is required
+    # in the backend driver for the call to succeed. A driver can
+    # provide a capability by implementing the method with the same
+    # name as the capability. Below is a list of the capabilities as
+    # the expected method signatures.
+    #
+    # Following the capability list are the resource member show
+    # methods. They each require that the corresponding collection
+    # method be defined
+    #
+    # TODO: standardize all of these to the same signature (credentials, opts)
+    #
+    # def realms(credentials, opts=nil)
+    #
+    # def images(credentials, ops)
+    #
+    # def instances(credentials, ops)
+    # def create_instance(credentials, image_id, opts)
+    # def start_instance(credentials, id)
+    # def stop_instance(credentials, id)
+    # def reboot_instance(credentials, id)
+    #
+    # def storage_volumes(credentials, ops)
+    #
+    # def storage_snapshots(credentials, ops)
+    #
+    # def buckets(credentials, opts = nil)
+    # def create_bucket(credentials, name, opts=nil)
+    # def delete_bucket(credentials, name, opts=nil)
+    #
+    # def blobs(credentials, opts = nil)
+    # def blob_data(credentials, bucket_id, blob_id, opts)
+    # def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
+    # def delete_blob(credentials, bucket_id, blob_id, opts=nil)
+    #
+    # def keys(credentials, opts)
+    # def create_key(credentials, opts)
+    # def destroy_key(credentials, opts)
+    #
+    # def firewalls(credentials, opts)
+    # def create_firewall(credentials, opts)
+    # def delete_firewall(credentials, opts)
+    # def create_firewall_rule(credentials, opts)
+    # def delete_firewall_rule(credentials, opts)
+    # def providers(credentials)
+    def realm(credentials, opts)
+      realms = realms(credentials, opts).first if has_capability?(:realms)
+    end
+
+    def image(credentials, opts)
+      images(credentials, opts).first if has_capability?(:images)
+    end
+
+    def instance(credentials, opts)
+      instances(credentials, opts).first if has_capability?(:instances)
+    end
+
+    def storage_volume(credentials, opts)
+      storage_volumes(credentials, opts).first if has_capability?(:storage_volumes)
+    end
+
+    def storage_snapshot(credentials, opts)
+      storage_snapshots(credentials, opts).first if has_capability?(:storage_snapshots)
+    end
+
+    def bucket(credentials, opts = {})
+      #list of objects within bucket
+      buckets(credentials, opts).first if has_capability?(:buckets)
+    end
+
+    def blob(credentials, opts = {})
+      blobs(credentials, opts).first if has_capability?(:blobs)
+    end
+
+    def key(credentials, opts=nil)
+      keys(credentials, opts).first if has_capability?(:keys)
+    end
+
+    def firewall(credentials, opts={})
+      firewalls(credentials, opts).first if has_capability?(:firewalls)
+    end
+
+    MEMBER_SHOW_METHODS =
+      [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key, :firewall ]
+
+    def filter_on(collection, attribute, opts)
+      return collection if opts.nil?
+      return collection if opts[attribute].nil?
+      filter = opts[attribute]
+      if ( filter.is_a?( Array ) )
+        return collection.select{|e| filter.include?( e.send(attribute) ) }
+      else
+        return collection.select{|e| filter == e.send(attribute) }
+      end
+    end
+
+    def supported_collections
+      DEFAULT_COLLECTIONS
+    end
+
+    def has_collection?(collection)
+      supported_collections.include?(collection)
+    end
+
+    def catched_exceptions_list
+      { :error => [], :auth => [], :glob => [] }
+    end
+
+    def api_provider
+      Thread.current[:provider] || ENV['API_PROVIDER']
+    end
+
+    # Return an array of the providers statically configured
+    # in the driver's YAML file
+    def configured_providers
+      []
+    end
+  end
+
+end
diff --git a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
index 2270178..8737a27 100644
--- a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
+++ b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
@@ -19,7 +19,7 @@ require 'deltacloud/drivers/ec2/ec2_driver.rb'
 module Deltacloud
   module Drivers
     module Eucalyptus
-      class EucalyptusDriver < EC2::EC2Driver
+      class EucalyptusDriver < Ec2::Ec2Driver
 
         def supported_collections
           DEFAULT_COLLECTIONS + [ :keys, :buckets, :addresses, :firewalls ]
diff --git a/server/lib/deltacloud/drivers/exceptions.rb b/server/lib/deltacloud/drivers/exceptions.rb
new file mode 100644
index 0000000..a89b05f
--- /dev/null
+++ b/server/lib/deltacloud/drivers/exceptions.rb
@@ -0,0 +1,191 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+module Deltacloud
+  module ExceptionHandler
+
+    class DeltacloudException < StandardError
+
+      attr_accessor :code, :name, :message, :backtrace, :request
+
+      def initialize(code, name, message, backtrace, request=nil)
+        @code, @name, @message = code, name, message
+        @backtrace = backtrace
+        @request = request
+        self
+      end
+
+    end
+
+    class AuthenticationFailure < DeltacloudException
+      def initialize(e, message=nil)
+        message ||= e.message
+        super(401, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class UnknownMediaTypeError < DeltacloudException
+      def initialize(e, message=nil)
+        message ||= e.message
+        super(406, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class MethodNotAllowed < DeltacloudException
+      def initialize(e, message=nil)
+        message ||= e.message
+        super(405, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class ValidationFailure < DeltacloudException
+      def initialize(e, message=nil)
+        message ||= e.message
+        super(400, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class BackendError < DeltacloudException
+      def initialize(e, message=nil)
+        message ||= e.message
+        super(500, e.class.name, message, e.backtrace, message)
+      end
+    end
+
+    class ProviderError < DeltacloudException
+      def initialize(e, message)
+        message ||= e.message
+        super(502, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class ProviderTimeout < DeltacloudException
+      def initialize(e, message)
+        message ||= e.message
+        super(504, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class NotImplemented < DeltacloudException
+      def initialize(e, message)
+        message ||= e.message
+        super(501, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class ObjectNotFound < DeltacloudException
+      def initialize(e, message)
+        message ||= e.message
+        super(404, e.class.name, message, e.backtrace)
+      end
+    end
+
+    class NotSupported < DeltacloudException
+      def initialize(message)
+        super(501, self.class.name, message, self.backtrace)
+      end
+    end
+
+    class ExceptionDef
+      attr_accessor :status
+      attr_accessor :message
+      attr_reader   :conditions
+      attr_reader   :handler
+
+      def initialize(conditions, &block)
+        @conditions = conditions
+        instance_eval(&block) if block_given?
+      end
+
+      def status(code)
+        self.status = code
+      end
+
+      def message(message)
+        self.message = message
+      end
+
+      def exception(handler)
+        self.handler = handler
+      end
+
+      # Condition can be class or regexp
+      #
+      def match?(e)
+        @conditions.each do |c|
+          return true if c.class == Class && e.class == c
+          return true if c.class == Regexp && (e.class.name =~ c or e.message =~ c)
+        end
+        return false
+      end
+
+      def handler(e)
+        return @handler if @handler
+        case @status
+          when 401 then Deltacloud::ExceptionHandler::AuthenticationFailure.new(e, @message)
+          when 404 then Deltacloud::ExceptionHandler::ObjectNotFound.new(e, @message)
+          when 406 then Deltacloud::ExceptionHandler::UnknownMediaTypeError.new(e, @message)
+          when 405 then Deltacloud::ExceptionHandler::MethodNotAllowed.new(e, @message)
+          when 400 then Deltacloud::ExceptionHandler::ValidationFailure.new(e, @message)
+          when 500 then Deltacloud::ExceptionHandler::BackendError.new(e, @message)
+          when 501 then Deltacloud::ExceptionHandler::NotImplemented.new(e, @message)
+          when 502 then Deltacloud::ExceptionHandler::ProviderError.new(e, @message)
+          when 504 then Deltacloud::ExceptionHandler::ProviderTimeout.new(e, @message)
+        end
+      end
+
+    end
+
+    class Exceptions
+      attr_reader :exception_definitions
+
+      def initialize(&block)
+        @exception_definitions = []
+        instance_eval(&block) if block_given?
+        self
+      end
+
+      def on(*conditions, &block)
+        @exception_definitions << ExceptionDef::new(conditions, &block) if block_given?
+      end
+    end
+
+    def self.exceptions(&block)
+      @definitions = Exceptions.new(&block).exception_definitions if block_given?
+      @definitions
+    end
+
+    def safely(&block)
+      begin
+        block.call
+      rescue
+        report_method = $stderr.respond_to?(:err) ? :err : :puts
+        Deltacloud::ExceptionHandler::exceptions.each do |exdef|
+          if exdef.match?($!)
+            new_exception = exdef.handler($!)
+            m = new_exception.message.nil? ? $!.message : new_exception.message
+            $stderr.send(report_method, "#{[$!.class.to_s, m].join(':')}\n#{$!.backtrace[0..10].join("\n")}")
+            raise exdef.handler($!) unless new_exception.nil?
+          end
+        end
+        $stderr.send(report_method, "[NO HANDLED] #{[$!.class.to_s, $!.message].join(': ')}\n#{$!.backtrace.join("\n")}")
+        raise Deltacloud::ExceptionHandler::BackendError.new($!, "Unhandled exception or status code (#{$!.message})")
+      end
+    end
+
+  end
+
+end
diff --git a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
index 371e170..cc05332 100644
--- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
+++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
@@ -15,7 +15,6 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'deltacloud/drivers/opennebula/occi_client'
 
 require 'erb'
diff --git a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
index 58f8e1b..391234b 100644
--- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
+++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
@@ -19,69 +19,62 @@
 
 require "net/http"
 require "net/https"
-require "rubygems"
-require "json"
-require "deltacloud/base_driver"
 
-module Deltacloud
-  module Drivers
-    module RimuHosting
+module Deltacloud::Drivers::RimuHosting
 
-class RimuHostingClient
-  def initialize(credentials ,baseuri = 'https://rimuhosting.com/r')
-    @uri = URI.parse(baseuri)
-    @service = Net::HTTP.new(@uri.host, @uri.port)
-    @service.use_ssl = true
-    @auth = "rimuhosting apikey=#{credentials.password}"
-  end
-
-  def request(resource, data='', method='GET')
-    headers = {"Accept" => "application/json", "Content-Type" => "application/json"}
-    if(!@auth.nil?)
-      headers["Authorization"] = @auth
+  class RimuHostingClient
+    def initialize(credentials ,baseuri = 'https://rimuhosting.com/r')
+      @uri = URI.parse(baseuri)
+      @service = Net::HTTP.new(@uri.host, @uri.port)
+      @service.use_ssl = true
+      @auth = "rimuhosting apikey=#{credentials.password}"
     end
-    safely do
-      r = @service.send_request(method, @uri.path + resource, data, headers)
-          puts r.body
-      res = JSON.parse(r.body)
-      res = res[res.keys[0]]
 
-      if(res['response_type'] == "ERROR" and ( (res['error_info']['error_class'] == "PermissionException") or
-					     (res['error_info']['error_class'] == "LoginRequired") ))
-        raise "AuthFailure"
+    def request(resource, data='', method='GET')
+      headers = {"Accept" => "application/json", "Content-Type" => "application/json"}
+      if(!@auth.nil?)
+        headers["Authorization"] = @auth
       end
-      res
-    end
-  end
+      safely do
+        r = @service.send_request(method, @uri.path + resource, data, headers)
+        puts r.body
+        res = JSON.parse(r.body)
+        res = res[res.keys[0]]
 
-  def list_images
-    request('/distributions')["distro_infos"]
-  end
+        if(res['response_type'] == "ERROR" and ( (res['error_info']['error_class'] == "PermissionException") or 
+                                                (res['error_info']['error_class'] == "LoginRequired") ))
+          raise "AuthFailure"
+        end
+        res
+      end
 
-  def list_plans
-    request('/pricing-plans;server-type=VPS')["pricing_plan_infos"]
-  end
+      def list_images
+        request('/distributions')["distro_infos"]
+      end
 
-  def list_nodes
-    request('/orders;include_inactive=N')["about_orders"]
-  end
+      def list_plans
+        request('/pricing-plans;server-type=VPS')["pricing_plan_infos"]
+      end
 
-  def set_server_state(id, state)
-    json = {"reboot_request" => {"running_state" => state}}.to_json
-    request("/orders/order-#{id}-a/vps/running-state", json, 'PUT')
-  end
+      def list_nodes
+        request('/orders;include_inactive=N')["about_orders"]
+      end
 
-  def delete_server(id)
-    request("/orders/order-#{id}-a/vps",'', 'DELETE')
-  end
+      def set_server_state(id, state)
+        json = {"reboot_request" => {"running_state" => state}}.to_json
+        request("/orders/order-#{id}-a/vps/running-state", json, 'PUT')
+      end
 
-  def create_server(image_id, plan_code, name)
-    json = {:new_vps => {:instantiation_options => {:domain_name => name, :distro => image_id},
-                        :pricing_plan_code => plan_code}}.to_json
-    request('/orders/new-vps',json, 'POST')[:about_order]
-  end
-end
+      def delete_server(id)
+        request("/orders/order-#{id}-a/vps",'', 'DELETE')
+      end
+
+      def create_server(image_id, plan_code, name)
+        json = {:new_vps => {:instantiation_options => {:domain_name => name, :distro => image_id},
+                             :pricing_plan_code => plan_code}}.to_json
+        request('/orders/new-vps',json, 'POST')[:about_order]
+      end
+    end
 
   end
 end
-end
diff --git a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
index 67c415c..4c2c3aa 100644
--- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
+++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
@@ -21,9 +21,9 @@ require "deltacloud/drivers/rimuhosting/rimuhosting_client"
 
 module Deltacloud
   module Drivers
-    module RimuHosting
+    module Rimuhosting
 
-class RimuHostingDriver < Deltacloud::BaseDriver
+class RimuhostingDriver < Deltacloud::BaseDriver
 
   feature :instances, :user_name
 
diff --git a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
index 2dba02a..9cc442c 100644
--- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
+++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
@@ -30,12 +30,11 @@ module Deltacloud
     module Terremark
 
 class TerremarkDriver < Deltacloud::BaseDriver
-
   feature :instances, :user_name do
-    constraint :max_length, 15
+    { :max_length => 50 }
   end
 
-  USER_NAME_MAX = feature(:instances, :user_name).constraints[:max_length]
+  USER_NAME_MAX = constraints(:collection => :instances, :feature => :user_name)[:max_length]
 
 #--
 # Vapp State Map... for use with convert_instance (get an integer back from terremark)
diff --git a/server/lib/deltacloud/helpers.rb b/server/lib/deltacloud/helpers.rb
index cf8531a..73f79ec 100644
--- a/server/lib/deltacloud/helpers.rb
+++ b/server/lib/deltacloud/helpers.rb
@@ -14,10 +14,84 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/helpers/application_helper'
-require 'deltacloud/helpers/json_helper'
-require 'deltacloud/helpers/conversion_helper'
-require 'deltacloud/helpers/hardware_profiles_helper'
-require 'deltacloud/helpers/blob_stream'
+require_relative 'helpers/driver_helper'
+require_relative 'helpers/auth_helper'
+require_relative 'helpers/url_helper'
+require_relative 'helpers/assets_helper'
+require_relative 'helpers/deltacloud_helper'
+require_relative 'helpers/rabbit_helper'
+require_relative 'helpers/blob_stream_helper'
+require_relative 'core_ext/string'
+require_relative 'core_ext/array'
+require_relative 'core_ext/hash'
+require_relative 'core_ext/integer'
+require_relative 'core_ext/proc'
 
-helpers ApplicationHelper, ConversionHelper, HardwareProfilesHelper, JSONHelper
+module Deltacloud::Collections
+  class Base < Sinatra::Base
+
+    extend Deltacloud::Helpers::Drivers
+    include Sinatra::Rabbit::Features
+
+    helpers Deltacloud::Helpers::Drivers
+    helpers Sinatra::AuthHelper
+    helpers Sinatra::UrlForHelper
+    helpers Sinatra::StaticAssets::Helpers
+    helpers Rack::RespondTo::Helpers
+    helpers Deltacloud::Helpers::Application
+
+    register Rack::RespondTo
+
+    enable :xhtml
+    enable :dump_errors
+    enable :show_errors
+    enable :method_override
+    disable :show_exceptions
+
+    set :root_url, API_ROOT_URL
+    set :version, API_VERSION
+    set :root, File.join(File.dirname(__FILE__), '..', '..')
+    set :views, root + '/views'
+    set :public_folder, root + '/public'
+
+    error do
+      report_error
+    end
+
+    error Deltacloud::ExceptionHandler::ValidationFailure do
+      report_error
+    end
+
+    before do
+      # Respond with 400, If we don't get a http Host header,
+      halt 400, "Unable to find HTTP Host header" if @env['HTTP_HOST'] == nil
+    end
+
+    after do
+      headers 'Server' => 'Apache-Deltacloud/' + settings.version
+    end
+
+    def self.new_route_for(route, &block)
+      get route_for('/' + route.to_s + '/new') do
+        instance_eval(&block) if block_given?
+        respond_to do |format|
+          format.html do
+            haml :"#{route}/new"
+          end
+        end
+      end
+    end
+
+    def self.check_capability(opts={})
+      Sinatra::Rabbit.set :check_capability, opts[:for]
+    end
+
+    def self.check_features(opts={})
+      Sinatra::Rabbit.set :check_features, opts[:for]
+    end
+
+    def self.route_for(url)
+      "#{settings.root_url}#{url}"
+    end
+  end
+end
diff --git a/server/lib/deltacloud/models.rb b/server/lib/deltacloud/models.rb
index af02520..099afda 100644
--- a/server/lib/deltacloud/models.rb
+++ b/server/lib/deltacloud/models.rb
@@ -1,4 +1,3 @@
-#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.  The
@@ -14,20 +13,11 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/models/base_model'
-require 'deltacloud/models/realm'
-require 'deltacloud/models/image'
-require 'deltacloud/models/instance'
-require 'deltacloud/models/key'
-require 'deltacloud/models/address'
-require 'deltacloud/models/instance_address'
-require 'deltacloud/models/instance_profile'
-require 'deltacloud/models/storage_snapshot'
-require 'deltacloud/models/storage_volume'
-require 'deltacloud/models/bucket'
-require 'deltacloud/models/blob'
-require 'deltacloud/models/load_balancer'
-require 'deltacloud/models/firewall'
-require 'deltacloud/models/firewall_rule'
-require 'deltacloud/models/provider'
-require 'deltacloud/models/metric'
+require_relative 'models/base_model'
+
+# Include all models
+
+Dir[File.join(File::dirname(__FILE__), "models", "*.rb")].each do |model|
+  next if model =~ /base_model\.rb$/
+  require model
+end
diff --git a/server/lib/deltacloud/models/hardware_profile.rb b/server/lib/deltacloud/models/hardware_profile.rb
new file mode 100644
index 0000000..45e77a1
--- /dev/null
+++ b/server/lib/deltacloud/models/hardware_profile.rb
@@ -0,0 +1,194 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+  class HardwareProfile
+
+    UNITS = {
+      :memory => "MB",
+      :storage => "GB",
+      :architecture => "label",
+      :cpu => "count"
+    }
+
+    def self.unit(name)
+      UNITS[name]
+    end
+
+    class Property
+      attr_reader :name, :kind, :default
+      # kind == :range
+      attr_reader :first, :last
+      # kind == :enum
+      attr_reader :values
+      # kind == :fixed
+      attr_reader :value
+
+      def initialize(name, values, opts = {})
+        @name = name
+        if values.is_a?(Range)
+          @kind = :range
+          @first = values.first
+          @last = values.last
+          @default = values.first
+        elsif values.is_a?(Array)
+          @kind = :enum
+          @values = values
+          @default = values.first
+        else
+          @kind = :fixed
+          @value = values
+          @default = @value
+        end
+        @default = opts[:default] if opts[:default]
+      end
+
+      def unit
+        HardwareProfile.unit(name)
+      end
+
+      def param
+        :"hwp_#{name}"
+      end
+
+      def fixed?
+        kind == :fixed
+      end
+
+      def valid?(v)
+        v = convert_property_value_type(v)
+        case kind
+          # NOTE:
+          # Currently we cannot validate fixed values because of UI
+          # limitation. In UI we have multiple hwp_* properties which overide
+          # each other.
+          # Then provider have one 'static' hardware profile and one
+          # 'customizable' when user select the static one the UI also send
+          # values from the customizable one (which will lead to a validation
+          # error because validation algorith will think that client want to
+          # overide fixed values.
+          #
+          # when :fixed then (v == @default.to_s)
+          when :fixed then true
+          when :range then match_type?(first, v) and (first..last).include?(v)
+          when :enum then match_type?(values.first, v) and values.include?(v)
+          else false
+        end
+      end
+
+      def to_param
+        if defined? Sinatra::Rabbit
+          Sinatra::Rabbit::Param.new([param, :string, :optional, []])
+        end
+      end
+
+      def include?(v)
+        if kind == :fixed
+          return v == value
+        else
+          return values.include?(v)
+        end
+      end
+
+      private
+
+      def match_type?(reference, value)
+        true if reference.class == value.class
+      end
+
+      def convert_property_value_type(v)
+        return v.to_f if v =~ /(\d+)\.(\d+)/
+        return v.to_i if v =~ /(\d+)/
+        v.to_s
+      end
+    end
+
+    class << self
+      def property(prop)
+        define_method(prop) do |*args|
+          values, opts, *ignored = *args
+          instvar = :"@#{prop}"
+          unless values.nil?
+            @properties[prop] = Property.new(prop, values, opts || {})
+          end
+          @properties[prop]
+        end
+      end
+    end
+
+    attr_reader :name
+    property :cpu
+    property :architecture
+    property :memory
+    property :storage
+
+    def initialize(name,&block)
+      @properties   = {}
+      @name         = name
+      instance_eval &block if block_given?
+    end
+
+    def each_property(&block)
+      @properties.each_value { |prop| yield prop }
+    end
+
+    def properties
+      @properties.values
+    end
+
+    def property(name)
+      @properties[name.to_sym]
+    end
+
+    def default?(prop, v)
+      p = @properties[prop.to_sym]
+      p && p.default.to_s == v
+    end
+
+    def to_hash
+      props = []
+      self.each_property do |p|
+        if p.kind.eql? :fixed
+          props << { :kind => p.kind, :value => p.value, :name => p.name, :unit => p.unit }
+        else
+          param = { :operation => "create", :method => "post", :name => p.name }
+          if p.kind.eql? :range
+            param[:range] = { :first => p.first, :last => p.last }
+          elsif p.kind.eql? :enum
+            param[:enum] = p.values.collect { |v| { :entry => v } }
+          end
+          param
+          props << { :kind => p.kind, :value => p.default, :name => p.name, :unit => p.unit, :param => param }
+        end
+      end
+      {
+        :id => self.name,
+        :properties => props
+      }
+    end
+
+    def include?(prop, v)
+      p = @properties[prop]
+      p.nil? || p.include?(v)
+    end
+
+    def params
+      @properties.values.inject([]) { |m, prop|
+        m << prop.to_param
+      }.compact
+    end
+  end
+end
diff --git a/server/lib/deltacloud/models/state_machine.rb b/server/lib/deltacloud/models/state_machine.rb
new file mode 100644
index 0000000..19fb9f2
--- /dev/null
+++ b/server/lib/deltacloud/models/state_machine.rb
@@ -0,0 +1,99 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+  class StateMachine
+
+    attr_reader :states
+    def initialize(&block)
+      @states  = []
+      instance_eval &block if block
+    end
+
+    def start()
+      state(:start)
+    end
+
+    def finish()
+      state(:finish)
+    end
+
+    def state(name)
+      state = @states.find{|e| e.name == name.to_sym}
+      if ( state.nil? )
+        state = State.new( self, name.to_sym )
+        @states << state
+      end
+      state
+    end
+
+    def method_missing(sym,*args)
+      return state( sym ) if ( args.empty? )
+      super( sym, *args )
+    end
+
+    class State
+
+      attr_reader :name
+      attr_reader :transitions
+
+      def initialize(machine, name)
+        @machine = machine
+        @name    = name
+        @transitions = []
+      end
+
+      def to_s
+        self.name.to_s
+      end
+
+      def to(destination_name)
+        destination = @machine.state(destination_name)
+        transition = Transition.new( @machine, destination )
+        @transitions << transition
+        transition
+      end
+
+    end
+
+    class Transition
+
+      attr_reader :destination
+      attr_reader :action
+
+      def initialize(machine, destination)
+        @machine = machine
+        @destination = destination
+        @auto   = false
+        @action = nil
+      end
+
+      def automatically
+        @auto = true
+      end
+
+      def automatically?
+        @auto
+      end
+
+      def on(action)
+        @action = action
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/state_machine.rb b/server/lib/deltacloud/state_machine.rb
deleted file mode 100644
index facd4ba..0000000
--- a/server/lib/deltacloud/state_machine.rb
+++ /dev/null
@@ -1,115 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud
-  class StateMachine
-
-    attr_reader :states
-    def initialize(opts = {}, &block)
-      @all_states = opts[:all_states]
-      @all_actions = opts[:all_actions]
-      @states  = []
-      instance_eval &block if block
-    end
-
-    def start()
-      state(:start)
-    end
-
-    def finish()
-      state(:finish)
-    end
-
-    def state(name)
-      unless valid_state_name?(name)
-        raise "State '#{name}' not in list of allowed states"
-      end
-      state = @states.find{|e| e.name == name.to_sym}
-      if ( state.nil? )
-        state = State.new( self, name.to_sym )
-        @states << state
-      end
-      state
-    end
-
-    def valid_state_name?(name)
-      @all_states.nil? || @all_states.include?(name.to_sym)
-    end
-
-    def valid_action_name?(name)
-      @all_actions.nil? || @all_actions.include?(name.to_sym)
-    end
-
-    def method_missing(sym,*args)
-      return state( sym ) if ( args.empty? )
-      super( sym, *args )
-    end
-
-    class State
-
-      attr_reader :name
-      attr_reader :transitions
-
-      def initialize(machine, name)
-        @machine = machine
-        @name    = name
-        @transitions = []
-      end
-
-      def to_s
-        self.name.to_s
-      end
-
-      def to(destination_name)
-        destination = @machine.state(destination_name)
-        transition = Transition.new( @machine, destination )
-        @transitions << transition
-        transition
-      end
-
-    end
-
-    class Transition
-
-      attr_reader :destination
-      attr_reader :action
-
-      def initialize(machine, destination)
-        @machine = machine
-        @destination = destination
-        @auto   = false
-        @action = nil
-      end
-
-      def automatically
-        @auto = true
-      end
-
-      def automatically?
-        @auto
-      end
-
-      def on(action)
-        unless @machine.valid_action_name?(action)
-          raise "Action '#{action}' not in list of allowed actions"
-        end
-        @action = action
-      end
-
-    end
-
-  end
-end
-- 
1.7.10.1


[PATCH core 46/51] Google: Partialy fixed the unit tests, added VCR version to Gemfile

Posted by mf...@redhat.com.
From: Michal Fojtik <mf...@redhat.com>


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/Gemfile                              |    2 +-
 server/tests/drivers/google/api_test.rb     |   17 +++---
 server/tests/drivers/google/buckets_test.rb |   13 +++--
 server/tests/drivers/google/common.rb       |   74 +++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 13 deletions(-)
 create mode 100644 server/tests/drivers/google/common.rb

diff --git a/server/Gemfile b/server/Gemfile
index 244814c..9bc9375 100644
--- a/server/Gemfile
+++ b/server/Gemfile
@@ -4,7 +4,7 @@ gemspec
 
 group :development do
   gem "compass", ">= 0.8.17"
-  gem "vcr"
+  gem "vcr", "<=1.11.3"
   gem "webmock"
   gem "rack-test", ">= 0.5.3"
   gem "ci_reporter"
diff --git a/server/tests/drivers/google/api_test.rb b/server/tests/drivers/google/api_test.rb
index bd86d95..88ff74d 100644
--- a/server/tests/drivers/google/api_test.rb
+++ b/server/tests/drivers/google/api_test.rb
@@ -1,30 +1,33 @@
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-
 module GoogleTest
 
   class ApiTest < Test::Unit::TestCase
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     def test_01_it_returns_entry_points
-      get_auth_url '/api;driver=google/?force_auth=1'
+      get_auth_url '/api?force_auth=1'
       (last_xml_response/'/api').first[:driver].should == 'google'
       (last_xml_response/'/api/link').length.should > 0
     end
 
     def test_02_it_has_google_features
-      get_url '/api;driver=google'
+      get_url '/api'
       features = (last_xml_response/'/api/link[@rel="buckets"]/feature').collect { |f| f[:name] }
       features.include?('bucket_location').should == true
       features.length.should == 1
     end
 
     def test_03_it_has_google_collections
-      get_url '/api;driver=google'
+      get_url '/api'
+      puts last_xml_response
       collections = (last_xml_response/'/api/link').collect { |f| f[:rel] }
       collections.include?('buckets').should == true
       collections.include?('drivers').should == true
diff --git a/server/tests/drivers/google/buckets_test.rb b/server/tests/drivers/google/buckets_test.rb
index dd4e065..dac8c87 100644
--- a/server/tests/drivers/google/buckets_test.rb
+++ b/server/tests/drivers/google/buckets_test.rb
@@ -1,13 +1,15 @@
-$:.unshift File.join(File.dirname(__FILE__), '..', '..', '..')
-require 'tests/common'
-#require 'webmock/test_unit'
 module GoogleTest
 
   class BucketsTest < Test::Unit::TestCase
     include Rack::Test::Methods
 
     def app
-      Sinatra::Application
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
     end
 
     @@bucket_name_google="#{@@created_bucket_name}googel"
@@ -75,7 +77,8 @@ module GoogleTest
                 :'api[driver]' => 'google'
                }
       head_url "/api/buckets/#{@@bucket_name_google}/#{@@blob_name_google}", params
-      last_response.status.should == 204
+      last_response.status.should == 200
+      puts last_response.body
       blob_meta_hash = last_response.headers.inject({}){|result, (k,v)| result[k]=v if k=~/^X-Deltacloud-Blobmeta-/i ; result}
       blob_meta_hash.gsub_keys(/x-.*meta-/i, "")
       ({"author"=>"deltacloud", "foo"=>"bar"}.eql?(blob_meta_hash)).should == true
diff --git a/server/tests/drivers/google/common.rb b/server/tests/drivers/google/common.rb
new file mode 100644
index 0000000..d9da302
--- /dev/null
+++ b/server/tests/drivers/google/common.rb
@@ -0,0 +1,74 @@
+ENV['API_DRIVER']   = "google"
+ENV['API_USER']     = 'GOOGK7JXLS6UEYS6AYVO'
+ENV['API_PASSWORD'] = 'QjxUunLgszKhBGn/LISQajGR82CfwvraxA9lqnkg'
+
+load File.join(File.dirname(__FILE__), '..', '..', 'common.rb')
+require 'vcr'
+
+DeltacloudTestCommon::record!
+
+VCR.config do |c|
+  c.cassette_library_dir = "#{File.dirname(__FILE__)}/fixtures/"
+  c.stub_with :excon
+  c.default_cassette_options = { :record => :new_episodes}
+end
+
+#monkey patch fix for VCR normalisation code:
+#see https://github.com/myronmarston/vcr/issues/4
+#when body is a tempfile, like when creating new blob
+#this method of normalisation fails and excon throws errors
+#(Excon::Errors::SocketError:can't convert Tempfile into String)
+#
+#RELEVANT: https://github.com/myronmarston/vcr/issues/101
+#(will need revisiting when vcr 2 comes along)
+
+module VCR
+  module Normalizers
+    module Body
+
+    private
+    def normalize_body
+     self.body = case body
+          when nil, ''; nil
+          else
+            String.new(body) unless body.is_a?(Tempfile)
+        end
+      end
+    end
+  end
+end
+
+module Deltacloud
+  module Test
+    include Rack::Test::Methods
+
+    def included?(sub)
+      sub.class_eval do
+        before do
+          header 'Accept', 'application/xml'
+        end
+      end
+    end
+
+    def xml_response
+      Nokogiri::XML(last_response.body)
+    end
+
+    def auth_as_mock
+      authorize ENV['API_USERNAME'], ENV['API_PASSWORD']
+    end
+
+    def collection_url(collection)
+      [Deltacloud[:root_url], collection.to_s].join('/')
+    end
+
+    def app
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
+    end
+  end
+end
-- 
1.7.10.1


Re: Deltacloud revamp using Sinatra::Base (rev 3 - final? ;-)

Posted by Ronelle Landy <rl...@redhat.com>.
ACK from QE

QE has tested the patch using Deltacloud to go out to live providers ec2, rhevm, vsphere both from the Deltacloud server and Ruby client.

----- Original Message -----
> From: mfojtik@redhat.com
> To: dev@deltacloud.apache.org
> Sent: Monday, May 21, 2012 6:06:41 AM
> Subject: Deltacloud revamp using Sinatra::Base (rev 3 - final? ;-)
> 
> Hi,
> 
> Sorry for the 'super-big-patch' once again, but this should be the
> final stable
> version with all nits and tests fixed so far.
> 
> The test that does not work include RHEV-M (vcr fixtures need to
> refresh).
> Revision 3 also include a basic test suite for the new library code
> to assure
> the drivers API is stable and various feature-related fixes,
> including the
> constraints settings.
> 
> The final code should run fine under Ruby 1.9 and also on Ruby 1.8.
> I don't have any github repo right now, because maintaing those turns
> to be a
> nightmare, since I need to rebase after every push.
> 
>   -- Michal
> 
>