deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@redhat.com
Subject [PATCH core 02/51] Core: Added new Sinatra::Base Deltacloud collection based on Sinatra::Rabbit
Date Mon, 21 May 2012 10:06:43 GMT
From: Michal Fojtik <mfojtik@redhat.com>


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


Mime
View raw message