You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2012/04/17 15:39:40 UTC

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

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


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

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


[PATCH core 13/32] Core: Removed old method mocking code, should be replaced by VCR

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 .../lib/deltacloud/drivers/ec2/ec2_mock_driver.rb  |  186 --------------------
 server/lib/deltacloud/method_serializer.rb         |   83 ---------
 2 files changed, 269 deletions(-)
 delete mode 100644 server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb
 delete mode 100644 server/lib/deltacloud/method_serializer.rb

diff --git a/server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb
deleted file mode 100644
index 03db2c1..0000000
--- a/server/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb
+++ /dev/null
@@ -1,186 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module RightAws
-  class MockEc2
-
-    def initialize(opts={})
-    end
-
-    def describe_images(id)
-      load_fixtures_for(:images).select { |i| i[:aws_id].eql?(id) }
-    end
-
-    def describe_images_by_owner(id)
-      load_fixtures_for(:images).select { |i| i[:aws_owner].eql?(id) }
-    end
-
-    def describe_images(opts={})
-      load_fixtures_for(:images)
-    end
-
-    def describe_availability_zones(opts={})
-      load_fixtures_for(:realms)
-    end
-
-    def describe_instances(opts={})
-      instances = load_fixtures_for(:instances)
-      instances.each_with_index do |instance, i|
-        instances[i] = update_delayed_state(instance)
-        return [instance] if opts and opts[:id] and instance[:aws_instance_id].eql?(opts[:id])
-      end
-      update_fixtures_for(:instances, instances)
-      instances
-    end
-
-    def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='', addressing_type = nil, instance_type = nil, kernel_id = nil, ramdisk_id = nil, availability_zone = nil, block_device_mappings = nil)
-
-      instances = load_fixtures_for(:instances)
-      image = load_fixtures_for(:images).select { |img| img[:aws_id].eql?(image_id) }.first
-
-      if availability_zone
-        realm = load_fixtures_for(:realms).select { |realm| realm[:zone_name].eql?(availability_zone) }.first
-      else
-        realm = load_fixtures_for(:realms).first
-      end
-
-      raise Exception unless image
-      raise Exception unless realm
-
-      instance = { }
-      instance[:aws_image_id] = image[:aws_id]
-      instance[:aws_availability_zone] = realm[:zone_name]
-      instance[:aws_instance_type] = instance_type
-      instance[:aws_owner] = user_data
-      instance[:aws_state] = 'pending'
-      instance[:aws_reason] = ''
-      instance[:dns_name] = "#{random_dns}-01-C9.usma2.compute.amazonaws.com"
-      instance[:private_dns_name] = "#{random_dns}-02-P9.usma2.compute.amazonaws.com"
-      instance[:aws_state_code] = "0"
-      instance[:aws_key_name] = "staging"
-      instance[:aws_kernel_id] = "aki-be3adfd7"
-      instance[:aws_ramdisk_id] = "ari-ce34gad7"
-      instance[:aws_groups] = ["default"]
-      instance[:aws_instance_id] = random_instance_id
-      instance[:aws_reservation_id] = "r-aabbccdd"
-      instance[:aws_launch_time] = instance_time_format
-
-      instances << instance
-
-      update_fixtures_for(:instances, instances)
-
-      return [instance]
-    end
-
-
-    def terminate_instances(id)
-      update_instance_state(id, 'stopping', '80')
-    end
-
-    def reboot_instances(id)
-      update_instance_state(id, 'pending', '0')
-    end
-
-    alias :destroy_instance :terminate_instances
-
-    def describe_snapshots(opts={})
-      load_fixtures_for(:storage_snapshot)
-    end
-
-    def describe_volumes(opts={})
-      load_fixtures_for(:storage_volume)
-    end
-
-    private
-
-    def driver_dir
-      File::expand_path(File::join(File::dirname(__FILE__), '../../../../features/support/ec2'))
-    end
-
-    def fixtures_path
-      File::expand_path(File::join(driver_dir, 'fixtures'))
-    end
-
-    def load_fixtures_for(collection)
-      YAML.load_file(File::join(fixtures_path, "#{collection}.yaml"))
-    end
-
-    def update_fixtures_for(collection, new_data)
-      File.open(File::join(fixtures_path, "#{collection}.yaml"), 'w' ) do |out|
-        YAML.dump(new_data, out)
-      end
-      return new_data
-    end
-
-    def instance_time_format
-      DateTime.now.to_s.gsub(/\+(.+)$/, '.000Z')
-    end
-
-    def random_instance_id
-      id_1 = ("%.4s" % Time.now.to_i.to_s.reverse).reverse
-      id_2 = ("%.3s" % Time.now.to_i.to_s.reverse)
-      "i-#{id_1}f#{id_2}"
-    end
-
-    def random_dns
-      "domU-#{rand(90)+10}-#{rand(90)+10}-#{rand(90)+10}-#{rand(90)+10}"
-    end
-
-    def update_delayed_state(instance)
-      time = DateTime.now - DateTime.parse(instance[:aws_launch_time])
-      hours, minutes, seconds, frac = Date.day_fraction_to_time(time)
-
-      if (minutes>(rand(2)+1) or hours>0) and instance[:aws_state].eql?('pending')
-        instance[:aws_state], instance[:aws_state_code] = 'running', '16'
-      end
-
-      if (minutes>(rand(1)+1) or hours>0) and instance[:aws_state].eql?('stopping')
-        instance[:aws_state], instance[:aws_state_code] = 'stopped', '80'
-      end
-
-      return instance
-    end
-
-    def update_instance_state(id, state, state_code)
-      instance = describe_instances(:id => id).first
-      if instance
-        instance[:aws_state], instance[:aws_state_code] = state, state_code
-        instance[:aws_launch_time] = instance_time_format
-        instances = load_fixtures_for(:instances)
-        instances.each_with_index do |inst, i|
-          instances[i] = instance if inst[:aws_instance_id].eql?(id)
-        end
-        update_fixtures_for(:instances, instances)
-        return instance
-      else
-        raise Exception
-      end
-    end
-
-  end
-end
-
-Deltacloud::Drivers::EC2::EC2Driver.class_eval do
-  alias_method :original_new_client, :new_client
-
-  def new_client(credentials, opts={})
-    if credentials.user != 'mockuser' and credentials.password != 'mockpassword'
-      raise "AuthFailure"
-    end
-    RightAws::MockEc2.new
-  end
-
-end
diff --git a/server/lib/deltacloud/method_serializer.rb b/server/lib/deltacloud/method_serializer.rb
deleted file mode 100644
index eec9abe..0000000
--- a/server/lib/deltacloud/method_serializer.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'base64'
-require 'digest'
-
-module MethodSerializer
-
-  module Cache
-
-    def cache_dir
-      storage_dir = $methods_cache_dir || File.join(File.dirname(__FILE__), 'cache')
-      class_dir = self.class.name.split('::').last
-      class_dir ||= self.class.name
-      File.join(storage_dir, class_dir.downcase)
-    end
-
-    def serialize_data(method_name, args, data)
-      File.open(cache_file_name(method_name, args), 'w') do |f|
-        f.puts(Base64.encode64(Marshal.dump(data)))
-      end
-      return data
-    end
-
-    def deserialize_data(method_name, args)
-      begin
-        data = File.readlines(cache_file_name(method_name, args)).join
-        Marshal.load(Base64.decode64(data))
-      rescue Errno::ENOENT
-        return false
-      end
-    end
-
-    def args_hash(args)
-      if args.class == Hash
-        args = args.to_a.collect {|i| [i[0].to_s, i[1]]}.sort
-      end
-      Digest::SHA1.hexdigest(args.to_s)
-    end
-
-    def cache_file_name(method_name, args)
-      FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
-      method_name = $scenario_prefix ? "#{$scenario_prefix}_#{method_name}" : method_name
-      File.join(cache_dir, "#{method_name}.#{args_hash(args)}")
-    end
-
-    def self.wrap_methods(c, opts={})
-      $methods_cache_dir = opts[:cache_dir]
-      $scenario_prefix = nil
-      c.class_eval do
-        cached_methods.each do |m|
-          next if c.instance_methods(false).include?("original_#{m}")
-          alias_method "original_#{m}".to_sym, m.to_sym
-          define_method m.to_sym do |*args|
-            args = args.first if args.size.eql?(1) and not args.first.class.eql?(Array)
-            output = deserialize_data(m, args)
-            unless output
-              output = method("original_#{m}".to_sym).to_proc[args]
-              return serialize_data(m, args, output)
-            else
-              return output
-            end
-          end
-        end
-      end
-    end
-
-  end
-
-end
-- 
1.7.10


[PATCH core 09/32] Core: Removed deprecated helpers

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/hardware_profile.rb          |  192 --------------
 .../lib/deltacloud/helpers/application_helper.rb   |  238 -----------------
 server/lib/deltacloud/helpers/assets_helper.rb     |   96 +++++++
 server/lib/deltacloud/helpers/auth_helper.rb       |   73 ++++++
 server/lib/deltacloud/helpers/blob_stream.rb       |  213 ---------------
 server/lib/deltacloud/helpers/conversion_helper.rb |   43 ---
 server/lib/deltacloud/helpers/deltacloud_helper.rb |  273 ++++++++++++++++++++
 server/lib/deltacloud/helpers/driver_helper.rb     |   57 ++++
 .../deltacloud/helpers/hardware_profiles_helper.rb |   50 ----
 server/lib/deltacloud/helpers/json_helper.rb       |   31 ---
 server/lib/deltacloud/helpers/rabbit_helper.rb     |   34 +++
 server/lib/deltacloud/helpers/url_helper.rb        |  112 ++++++++
 12 files changed, 645 insertions(+), 767 deletions(-)
 delete mode 100644 server/lib/deltacloud/hardware_profile.rb
 delete mode 100644 server/lib/deltacloud/helpers/application_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/assets_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/auth_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/blob_stream.rb
 delete mode 100644 server/lib/deltacloud/helpers/conversion_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/deltacloud_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/driver_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/hardware_profiles_helper.rb
 delete mode 100644 server/lib/deltacloud/helpers/json_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/rabbit_helper.rb
 create mode 100644 server/lib/deltacloud/helpers/url_helper.rb

diff --git a/server/lib/deltacloud/hardware_profile.rb b/server/lib/deltacloud/hardware_profile.rb
deleted file mode 100644
index 162f7af..0000000
--- a/server/lib/deltacloud/hardware_profile.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud
-  class HardwareProfile
-
-    UNITS = {
-      :memory => "MB",
-      :storage => "GB",
-      :architecture => "label",
-      :cpu => "count"
-    }
-
-    def self.unit(name)
-      UNITS[name]
-    end
-
-    class Property
-      attr_reader :name, :kind, :default
-      # kind == :range
-      attr_reader :first, :last
-      # kind == :enum
-      attr_reader :values
-      # kind == :fixed
-      attr_reader :value
-
-      def initialize(name, values, opts = {})
-        @name = name
-        if values.is_a?(Range)
-          @kind = :range
-          @first = values.first
-          @last = values.last
-          @default = values.first
-        elsif values.is_a?(Array)
-          @kind = :enum
-          @values = values
-          @default = values.first
-        else
-          @kind = :fixed
-          @value = values
-          @default = @value
-        end
-        @default = opts[:default] if opts[:default]
-      end
-
-      def unit
-        HardwareProfile.unit(name)
-      end
-
-      def param
-        :"hwp_#{name}"
-      end
-
-      def fixed?
-        kind == :fixed
-      end
-
-      def valid?(v)
-        v = convert_property_value_type(v)
-        case kind
-          # NOTE:
-          # Currently we cannot validate fixed values because of UI
-          # limitation. In UI we have multiple hwp_* properties which overide
-          # each other.
-          # Then provider have one 'static' hardware profile and one
-          # 'customizable' when user select the static one the UI also send
-          # values from the customizable one (which will lead to a validation
-          # error because validation algorith will think that client want to
-          # overide fixed values.
-          #
-          # when :fixed then (v == @default.to_s)
-          when :fixed then true
-          when :range then match_type?(first, v) and (first..last).include?(v)
-          when :enum then match_type?(values.first, v) and values.include?(v)
-          else false
-        end
-      end
-
-      def to_param
-        Validation::Param.new([param, :string, :optional, []])
-      end
-
-      def include?(v)
-        if kind == :fixed
-          return v == value
-        else
-          return values.include?(v)
-        end
-      end
-
-      private
-
-      def match_type?(reference, value)
-        true if reference.class == value.class
-      end
-
-      def convert_property_value_type(v)
-        return v.to_f if v =~ /(\d+)\.(\d+)/
-        return v.to_i if v =~ /(\d+)/
-        v.to_s
-      end
-    end
-
-    class << self
-      def property(prop)
-        define_method(prop) do |*args|
-          values, opts, *ignored = *args
-          instvar = :"@#{prop}"
-          unless values.nil?
-            @properties[prop] = Property.new(prop, values, opts || {})
-          end
-          @properties[prop]
-        end
-      end
-    end
-
-    attr_reader :name
-    property :cpu
-    property :architecture
-    property :memory
-    property :storage
-
-    def initialize(name,&block)
-      @properties   = {}
-      @name         = name
-      instance_eval &block if block_given?
-    end
-
-    def each_property(&block)
-      @properties.each_value { |prop| yield prop }
-    end
-
-    def properties
-      @properties.values
-    end
-
-    def property(name)
-      @properties[name.to_sym]
-    end
-
-    def default?(prop, v)
-      p = @properties[prop.to_sym]
-      p && p.default.to_s == v
-    end
-
-    def to_hash
-      props = []
-      self.each_property do |p|
-        if p.kind.eql? :fixed
-          props << { :kind => p.kind, :value => p.value, :name => p.name, :unit => p.unit }
-        else
-          param = { :operation => "create", :method => "post", :name => p.name }
-          if p.kind.eql? :range
-            param[:range] = { :first => p.first, :last => p.last }
-          elsif p.kind.eql? :enum
-            param[:enum] = p.values.collect { |v| { :entry => v } }
-          end
-          param
-          props << { :kind => p.kind, :value => p.default, :name => p.name, :unit => p.unit, :param => param }
-        end
-      end
-      {
-        :id => self.name,
-        :properties => props
-      }
-    end
-
-    def include?(prop, v)
-      p = @properties[prop]
-      p.nil? || p.include?(v)
-    end
-
-    def params
-      @properties.values.inject([]) { |m, prop|
-        m << prop.to_param
-      }.compact
-    end
-  end
-end
diff --git a/server/lib/deltacloud/helpers/application_helper.rb b/server/lib/deltacloud/helpers/application_helper.rb
deleted file mode 100644
index 7a0d58b..0000000
--- a/server/lib/deltacloud/helpers/application_helper.rb
+++ /dev/null
@@ -1,238 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-# Methods added to this helper will be available to all templates in the application.
-
-require 'benchmark'
-
-module ApplicationHelper
-
-  include Deltacloud
-
-  def instance_action_method(action)
-    action_method(action, :instances)
-  end
-
-  def action_method(action, collection)
-    collections[collection].operations[action.to_sym].method
-  end
-
-  def driver_has_feature?(feature_name, collection_name = :instances)
-    driver.features(collection_name).any? { |f| f.name == feature_name }
-  end
-
-  def driver_has_auth_features?
-    driver_has_feature?(:authentication_password) || driver_has_feature?(:authentication_key)
-  end
-
-  def driver_auth_feature_name
-    'key' if driver_has_feature?(:authentication_key)
-    'password' if driver_has_feature?(:authentication_password)
-  end
-
-  def filter_all(model)
-      filter = {}
-      filter.merge!(:id => params[:id]) if params[:id]
-      filter.merge!(:architecture => params[:architecture]) if params[:architecture]
-      filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
-      filter.merge!(:state => params[:state]) if params[:state]
-      filter = {} if filter.keys.size.eql?(0)
-      singular = model.to_s.singularize.to_sym
-      begin
-       @benchmark = Benchmark.measure do
-          @elements = driver.send(model.to_sym, credentials, filter)
-        end
-      rescue
-        @exception = $!
-      end
-      if @elements
-        headers['X-Backend-Runtime'] = @benchmark.real.to_s
-        instance_variable_set(:"@#{model}", @elements)
-        respond_to do |format|
-          format.html { haml :"#{model}/index" }
-          format.xml { haml :"#{model}/index" }
-          format.json { convert_to_json(singular, @elements) }
-        end
-      else
-        report_error(@exception.code)
-      end
-  end
-
-  def show(model)
-    @benchmark = Benchmark.measure do
-      @element = driver.send(model, credentials, { :id => params[:id]} )
-    end
-    headers['X-Backend-Runtime'] = @benchmark.real.to_s
-    instance_variable_set("@#{model}", @element)
-    if @element
-      respond_to do |format|
-        format.html { haml :"#{model.to_s.pluralize}/show" }
-        format.xml { haml :"#{model.to_s.pluralize}/show" }
-        format.json { convert_to_json(model, @element) }
-      end
-    else
-      report_error(404)
-    end
-  end
-
-  def report_error(code=nil)
-    @error, @code = (request.env['sinatra.error'] || @exception), code
-    @code = 500 if not @code and not @error.class.method_defined? :code
-    response.status = @code || @error.code
-    respond_to do |format|
-      format.xml {  haml :"errors/#{@code || @error.code}", :layout => false }
-      format.json { json_return_error(@error) }
-      format.html { haml :"errors/#{@code || @error.code}", :layout => :error }
-    end
-  end
-
-  def instance_action(name)
-    original_instance = driver.instance(credentials, :id => params[:id])
-
-    # If original instance doesn't include called action
-    # return with 405 error (Method is not Allowed)
-    unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
-      return report_error(405)
-    end
-
-    @benchmark = Benchmark.measure do
-      @instance = driver.send(:"#{name}_instance", credentials, params[:id])
-    end
-
-    headers['X-Backend-Runtime'] = @benchmark.real.to_s
-
-    if name == :reboot
-      status 202
-    end
-
-    if name == :destroy
-      respond_to do |format|
-        format.xml { return 204 }
-        format.json { return 204 }
-        format.html { return redirect(instances_url) }
-      end
-    end
-
-    if @instance.class != Instance
-      response['Location'] = instance_url(params[:id])
-      halt
-    end
-
-    respond_to do |format|
-      format.xml { haml :"instances/show" }
-      format.html { haml :"instances/show" }
-      format.json {convert_to_json(:instance, @instance) }
-    end
-  end
-
-  def cdata(text = nil, &block)
-    text ||= capture_haml(&block)
-    "<![CDATA[#{text.strip}]]>"
-  end
-
-  def render_cdata(text)
-    "<![CDATA[#{text.strip}]]>"
-  end
-
-  def link_to_action(action, url, method)
-    capture_haml do
-      haml_tag :form, :method => :post, :action => url, :class => [:link, method], :'data-ajax' => 'false' do
-        haml_tag :input, :type => :hidden, :name => '_method', :value => method
-        haml_tag :button, :type => :submit, :'data-ajax' => 'false', :'data-inline' => "true" do
-          haml_concat action
-        end
-      end
-    end
-  end
-
-  def link_to_format(format)
-    return unless request.env['REQUEST_URI']
-    uri = request.env['REQUEST_URI']
-    return if uri.include?('format=')
-    uri += uri.include?('?') ? "&format=#{format}" : "?format=#{format}"
-    capture_haml do
-      haml_tag :a, :href => uri, :'data-ajax' => 'false', :'data-icon' => 'grid' do
-        haml_concat format.to_s.upcase
-      end
-    end
-  end
-
-  def image_for_state(state)
-    state_img = "stopped" if (state!='RUNNING' or state!='PENDING')
-    capture_haml do
-      haml_tag :img, :src => "/images/#{state}" % state.downcase, :title => state
-    end
-  end
-
-  # Reverse the entrypoints hash for a driver from drivers.yaml; note that
-  # +d+ is a hash, not an actual driver object
-  def driver_provider(d)
-    result = {}
-    if d[:entrypoints]
-      d[:entrypoints].each do |kind, details|
-        details.each do |prov, url|
-          result[prov] ||= {}
-          result[prov][kind] = url
-        end
-      end
-    end
-    result
-  end
-
-  def header(title, opts={}, &block)
-    opts[:theme] ||= 'b'
-    opts[:back] ||= 'true'
-    capture_haml do
-      haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme], :'data-add-back-btn' => opts[:back] do
-        haml_tag :a, :'data-rel' => :back do
-          haml_concat "Back"
-        end if opts[:back] == 'true'
-        haml_tag :h1 do
-          haml_concat title
-        end
-        block.call if block_given?
-      end
-    end
-  end
-
-  def subheader(title, opts={})
-    opts[:theme] ||= 'a'
-    capture_haml do
-      haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme] do
-        haml_tag :p, :class => 'inner-right' do
-          haml_concat title
-        end
-      end
-    end
-  end
-
-  def translate_error_code(code)
-    case code
-      when 400; { :message => "Bad Request" }
-      when 401; { :message => "Unauthorized" }
-      when 403; { :message => "Forbidden" }
-      when 404; { :message => "Not Found" }
-      when 405; { :message => "Method Not Allowed" }
-      when 406; { :message => "Not Acceptable" }
-      when 500; { :message => "Internal Server Error" }
-      when 502; { :message => "Backend Server Error" }
-      when 501; { :message => "Not Supported" }
-    end
-  end
-
-  def new_blob_form_url(bucket)
-    bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
-  end
-end
diff --git a/server/lib/deltacloud/helpers/assets_helper.rb b/server/lib/deltacloud/helpers/assets_helper.rb
new file mode 100644
index 0000000..2391da7
--- /dev/null
+++ b/server/lib/deltacloud/helpers/assets_helper.rb
@@ -0,0 +1,96 @@
+#
+# 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 Sinatra
+  module StaticAssets
+    module Helpers
+      # In HTML <link> and <img> tags have no end tag.
+      # In XHTML, on the contrary, these tags must be properly closed.
+      #
+      # We can choose the appropriate behaviour with +closed+ option:
+      #
+      #   image_tag "/images/foo.png", :alt => "Foo itself", :closed => true
+      #
+      # The default value of +closed+ option is +false+.
+      #
+      def image_tag(source, options = {})
+        options[:src] = url_for(source)
+        tag("img", options)
+      end
+
+      def stylesheet_link_tag(*sources)
+        list, options = extract_options(sources)
+        list.collect { |source| stylesheet_tag(source, options) }.join("\n")
+      end
+
+      def javascript_script_tag(*sources)
+        list, options = extract_options(sources)
+        list.collect { |source| javascript_tag(source, options) }.join("\n")
+      end
+
+      def link_to(desc, url, options = {})
+        tag("a", options.merge(:href => url_for(url))) do
+          desc
+        end
+      end
+
+      private
+
+      def tag(name, local_options = {})
+        start_tag = "<#{name}#{tag_options(local_options) if local_options}"
+        if block_given?
+          content = yield
+          "#{start_tag}>#{content}</#{name}>"
+        else
+          "#{start_tag}#{"/" if settings.xhtml}>"
+        end
+      end
+
+      def tag_options(options)
+        unless options.empty?
+          attrs = []
+          attrs = options.map { |key, value| %(#{key}="#{Rack::Utils.escape_html(value)}") }
+          " #{attrs.sort * ' '}" unless attrs.empty?
+        end
+      end
+
+      def stylesheet_tag(source, options = {})
+        tag("link", { :type => "text/css",
+            :charset => "utf-8", :media => "screen", :rel => "stylesheet",
+            :href => url_for(source) }.merge(options))
+      end
+
+      def javascript_tag(source, options = {})
+        tag("script", { :type => "text/javascript", :charset => "utf-8",
+            :src => url_for(source) }.merge(options)) do
+            end
+      end
+
+      def extract_options(a)
+        opts = a.last.is_a?(::Hash) ? a.pop : {}
+        [a, opts]
+      end
+
+    end
+
+    def self.registered(app)
+      app.helpers StaticAssets::Helpers
+      app.disable :xhtml
+    end
+  end
+
+  register StaticAssets
+end
diff --git a/server/lib/deltacloud/helpers/auth_helper.rb b/server/lib/deltacloud/helpers/auth_helper.rb
new file mode 100644
index 0000000..eef2521
--- /dev/null
+++ b/server/lib/deltacloud/helpers/auth_helper.rb
@@ -0,0 +1,73 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+# Lazy Basic HTTP authentication. Authentication is only forced when the
+# credentials are actually needed.
+
+module Sinatra
+  module AuthHelper
+    class LazyCredentials
+      def initialize(app)
+        @app = app
+        @provided = false
+      end
+
+      def user
+        credentials!
+        @user
+      end
+
+      def password
+        credentials!
+        @password
+      end
+
+      def provided?
+        @provided
+      end
+
+      private
+      def credentials!
+        if ENV["API_USER"] && ENV["API_PASSWORD"]
+          @user = ENV["API_USER"]
+          @password = ENV["API_PASSWORD"]
+          @provided = true
+        end
+        unless provided?
+          auth = Rack::Auth::Basic::Request.new(@app.request.env)
+          @app.authorize! unless auth.provided? && auth.basic? && auth.credentials
+          @user = auth.credentials[0]
+          @password = auth.credentials[1]
+          @provided = true
+        end
+      end
+
+    end
+
+    def authorize!
+      r = "#{Thread.current[:driver]}-deltacloud@#{ENV['HOSTNAME']}"
+      response['WWW-Authenticate'] = %(Basic realm="#{r}")
+      throw(:halt, [401, report_error(401)])
+    end
+
+    # Request the current user's credentials. Actual credentials are only
+    # requested when an attempt is made to get the user name or password
+    def credentials
+      LazyCredentials.new(self)
+    end
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/blob_stream.rb b/server/lib/deltacloud/helpers/blob_stream.rb
deleted file mode 100644
index df5cdc6..0000000
--- a/server/lib/deltacloud/helpers/blob_stream.rb
+++ /dev/null
@@ -1,213 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-include Deltacloud
-begin
-  require 'eventmachine'
-  #--
-  # based on the example from
-  #   http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/
-  #--
-  class BlobStream
-    AsyncResponse = [-1, {}, []].freeze
-    def self.call(env, credentials, params)
-      body = DeferrableBody.new
-      #Get the headers out asap. Don't specify a content-type let
-      #the client guess and if they can't they SHOULD default to
-      #'application/octet-stream' anyway as per:
-      #http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
-      EM.next_tick { env['async.callback'].call [200, {
-        'Content-Type' => "#{params['content_type']}",
-        'Content-Disposition' => params["content_disposition"],
-        'Content-Length' => "#{params['content_length']}"}, body]
-      }
-      #call the driver from here. the driver method yields for every chunk
-      #of blob it receives. Then use body.call to write that chunk as received.
-      driver.blob_data(credentials, params[:bucket], params[:blob], params) {|chunk| body.call ["#{chunk}"]} #close blob_data block
-      body.succeed
-      AsyncResponse # Tell Thin to not close connection & work other requests
-    end
-  end
-
-  class DeferrableBody
-    include EventMachine::Deferrable
-
-    def call(body)
-      body.each do |chunk|
-        @body_callback.call(chunk)
-      end
-    end
-
-    def each(&blk)
-      @body_callback = blk
-    end
-  end
-rescue LoadError => e
-  # EventMachine isn't available, disable blob streaming
-  class BlobStream
-    def self.call(env, credentials, params)
-      raise NotImplementedError.new("Blob streaming is only supported under Thin")
-    end
-  end
-end
-
-module BlobHelper
-
-  def self.extract_blob_metadata_hash(env_hash)
-    meta_array = env_hash.select{|k,v| k.match(/^HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i)}
-    metadata = meta_array.inject({}){ |result, array| result[array.first.upcase] = array.last; result}
-    metadata
-  end
-
-DELTACLOUD_BLOBMETA_HEADER = /HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i
-
-  #e.g. from HTTP-X-Deltacloud-Blobmeta-FOO:BAR to amz-meta-FOO:BAR
-  def self.rename_metadata_headers(metadata, rename_to)
-    metadata.gsub_keys(DELTACLOUD_BLOBMETA_HEADER, rename_to)
-  end
-
-end
-
-#Monkey patch for streaming blobs:
-# Normally a client will upload a blob to deltacloud and thin will put
-# this into a tempfile. Then deltacloud would stream up to the provider:
-#   i.e.  client =-->>TEMP_FILE-->> deltacloud =-->>STREAM-->> provider
-# Instead we want to recognise that this is a 'PUT blob' operation and
-# start streaming to the provider as the request is received:
-#   i.e.  client =-->>STREAM-->> deltacloud =-->>STREAM-->> provider
-module Thin
-  class Request
-
-    alias_method :move_body_to_tempfile_orig, :move_body_to_tempfile if defined?(Thin::Response)
-    private
-      def move_body_to_tempfile
-        if BlobStreamIO::is_put_blob(self)
-          @body = BlobStreamIO.new(self)
-        else
-          move_body_to_tempfile_orig
-        end
-      end
-
-  end
-end
-
-require 'net/http'
-require 'net/https'
-#monkey patch for Net:HTTP
-module Net
-  class HTTP
-
-    alias :request_orig :request
-
-    def request(req, body = nil, blob_stream = nil, &block)
-      unless blob_stream
-        return request_orig(req, body, &block)
-      end
-      @blob_req = req
-      do_start #start the connection
-
-      req.set_body_internal body
-      begin_transport req
-      req.write_header_m @socket,@curr_http_version, edit_path(req.path)
-      @socket
-    end
-
-    class Put < HTTPRequest
-      def write_header_m(sock, ver, path)
-        write_header(sock, ver, path)
-      end
-    end
-
-    def end_request
-      begin
-        res = HTTPResponse.read_new(@socket)
-      end while res.kind_of?(HTTPContinue)
-      res.reading_body(@socket, @blob_req.response_body_permitted?) {
-                                          yield res if block_given? }
-      end_transport @blob_req, res
-      do_finish
-      res
-    end
-  end
-
-end
-
-require 'base64'
-class BlobStreamIO
-
-  attr_accessor :size, :provider, :sock
-
-  def initialize(request)
-    @client_request = request
-    @size = 0
-    bucket, blob = parse_bucket_blob(request.env["PATH_INFO"])
-    user, password = parse_credentials(request.env['HTTP_AUTHORIZATION'])
-    content_type = request.env['CONTENT_TYPE'] || ""
-    #deal with blob_metadata: (X-Deltacloud-Blobmeta-name: value)
-    user_meta = BlobHelper::extract_blob_metadata_hash(request.env)
-    @content_length = request.env['CONTENT_LENGTH']
-    @http, provider_request = driver.blob_stream_connection({:user=>user,
-       :password=>password, :bucket=>bucket, :blob=>blob, :metadata=> user_meta,
-       :content_type=>content_type, :content_length=>@content_length })
-    @content_length = @content_length.to_i #for comparison of size in '<< (data)'
-    @sock = @http.request(provider_request, nil, true)
-  end
-
-  def << (data)
-    @sock.write(data)
-    @size += data.length
-    if (@size >= @content_length)
-      result = @http.end_request
-      if result.is_a?(Net::HTTPSuccess)
-        @client_request.env["BLOB_SUCCESS"] = "true"
-      else
-        @client_request.env["BLOB_FAIL"] = result.body
-      end
-    end
-  end
-
-  def rewind
-  end
-
-  #use the Request.env hash (populated by the ThinParser) to determine whether
-  #this is a post blob operation. By definition, only get here with a body of
-  # > 112kbytes - thin/lib/thin/request.rb:12 MAX_BODY = 1024 * (80 + 32)
-  def self.is_put_blob(request = nil)
-    path = request.env['PATH_INFO']
-    method = request.env['REQUEST_METHOD']
-    if ( path =~ /^#{Regexp.escape(settings.root_url)}\/buckets/ && method == 'PUT' )
-      return true
-    else
-      return false
-    end
-  end
-
-  private
-
-  def parse_bucket_blob(request_string)
-    array = request_string.split("/")
-    blob = array.pop
-    bucket = array.pop
-    return bucket, blob
-  end
-
-  def parse_credentials(request_string)
-    decoded = Base64.decode64(request_string.split('Basic ').last)
-    key = decoded.split(':').first
-    pass = decoded.split(':').last
-    return key, pass
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/conversion_helper.rb b/server/lib/deltacloud/helpers/conversion_helper.rb
deleted file mode 100644
index 310ba4b..0000000
--- a/server/lib/deltacloud/helpers/conversion_helper.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-require 'deltacloud/base_driver'
-
-module ConversionHelper
-
-  def convert_to_json(type, obj)
-    if ( [ :image, :realm, :instance, :storage_volume, :storage_snapshot, :hardware_profile, :key, :bucket, :blob, :firewall, :load_balancer, :address ].include?( type ) )
-      if Array.eql?(obj.class)
-        data = obj.collect do |o|
-          o.to_hash.merge({ :href => self.send(:"#{type}_url", type.eql?(:hardware_profile) ? o.name : o.id ) })
-        end
-        type = type.to_s.pluralize
-      else
-        data = obj.to_hash
-        if type == :blob
-          data.merge!({ :href => self.send(:"bucket_url", "#{data[:bucket]}/#{data[:id]}" ) })
-        else
-          data.merge!({ :href => self.send(:"#{type}_url", data[:id]) })
-          if data.has_key?(:hardware_profiles)
-            data[:hardware_profiles] = data[:hardware_profiles].inject([]){|res, hwp| res << {hwp.name => {:href => self.send(:"hardware_profile_url", hwp.name)}}; res }
-          end
-        end
-      end
-      return { :"#{type}" => data }.to_json
-    end
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/deltacloud_helper.rb b/server/lib/deltacloud/helpers/deltacloud_helper.rb
new file mode 100644
index 0000000..83741f9
--- /dev/null
+++ b/server/lib/deltacloud/helpers/deltacloud_helper.rb
@@ -0,0 +1,273 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Helpers
+  module Application
+
+    require 'benchmark'
+
+    def self.included(klass)
+      klass.class_eval do
+        set :root_url, API_ROOT_URL
+        include Sinatra::Rabbit
+        Sinatra::Rabbit.set :root_path, root_url+'/'
+      end
+    end
+
+    def instance_action_method(action)
+      action_method(action, Sinatra::Rabbit::InstancesCollection)
+    end
+
+    def action_method(action, collection)
+      http_method = collection.operation(action).http_method
+      http_method || Sinatra::Rabbit::BaseCollection.http_method_for(action)
+    end
+
+    def filter_all(model)
+      filter = {}
+      filter.merge!(:id => params[:id]) if params[:id]
+      filter.merge!(:architecture => params[:architecture]) if params[:architecture]
+      filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
+      filter.merge!(:state => params[:state]) if params[:state]
+      filter = {} if filter.keys.size.eql?(0)
+      singular = model.to_s.singularize.to_sym
+      begin
+        @benchmark = Benchmark.measure do
+          @elements = driver.send(model.to_sym, credentials, filter)
+        end
+      rescue
+        @exception = $!
+      end
+      if @elements
+        headers['X-Backend-Runtime'] = @benchmark.real.to_s
+        instance_variable_set(:"@#{model}", @elements)
+        respond_to do |format|
+          format.html { haml :"#{model}/index" }
+          format.xml { haml :"#{model}/index" }
+          format.json { @media_type=:xml; to_json(haml(:"#{model}/index")) }
+        end
+      else
+        report_error(@exception.respond_to?(:code) ? @exception.code : 500)
+      end
+    end
+
+    def xml_to_json(model)
+      @media_type = :xml
+      to_json(haml(:"#{model}"))
+    end
+
+    def to_json(xml)
+      Crack::XML.parse(xml).to_json
+    end
+
+    def show(model)
+      @benchmark = Benchmark.measure do
+        @element = driver.send(model, credentials, { :id => params[:id]} )
+      end
+      headers['X-Backend-Runtime'] = @benchmark.real.to_s
+      instance_variable_set("@#{model}", @element)
+      if @element
+        respond_to do |format|
+          format.html { haml :"#{model.to_s.pluralize}/show" }
+          format.xml { haml :"#{model.to_s.pluralize}/show" }
+          format.json { @media_type=:xml; to_json(haml(:"#{model.to_s.pluralize}/show")) }
+        end
+      else
+        report_error(404)
+      end
+    end
+
+    def report_error(code=nil)
+      @error, @code = (request.env['sinatra.error'] || @exception), code
+      @code = 500 if not @code and not @error.class.method_defined? :code
+      response.status = @code || @error.code
+      respond_to do |format|
+        format.xml {  haml :"errors/#{@code || @error.code}", :layout => false }
+        format.html { haml :"errors/#{@code || @error.code}", :layout => :error }
+      end
+    end
+
+    def instance_action(name)
+      original_instance = driver.instance(credentials, :id => params[:id])
+
+      # If original instance doesn't include called action
+      # return with 405 error (Method is not Allowed)
+      unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
+        return report_error(405)
+      end
+
+      @benchmark = Benchmark.measure do
+        @instance = driver.send(:"#{name}_instance", credentials, params[:id])
+      end
+
+      headers['X-Backend-Runtime'] = @benchmark.real.to_s
+      status 202
+
+      if name == :destroy
+        respond_to do |format|
+          format.xml { return 204 }
+          format.json { return 204 }
+          format.html { return redirect(instances_url) }
+        end
+      end
+
+      if @instance.class != Instance
+        response['Location'] = instance_url(params[:id])
+        halt
+      end
+
+      respond_to do |format|
+        format.xml { haml :"instances/show" }
+        format.html { haml :"instances/show" }
+        format.json {convert_to_json(:instance, @instance) }
+      end
+    end
+
+    def cdata(text = nil, &block)
+      text ||= capture_haml(&block)
+      "<![CDATA[#{text.strip}]]>"
+    end
+
+    def render_cdata(text)
+      "<![CDATA[#{text.strip}]]>"
+    end
+
+    def link_to_action(action, url, method)
+      capture_haml do
+        haml_tag :form, :method => :post, :action => url, :class => [:link, method], :'data-ajax' => 'false' do
+          haml_tag :input, :type => :hidden, :name => '_method', :value => method
+          haml_tag :button, :type => :submit, :'data-ajax' => 'false', :'data-inline' => "true" do
+            haml_concat action
+          end
+        end
+      end
+    end
+
+    def link_to_format(format)
+      return unless request.env['REQUEST_URI']
+      uri = request.env['REQUEST_URI']
+      return if uri.include?('format=')
+      uri += uri.include?('?') ? "&format=#{format}" : "?format=#{format}"
+      capture_haml do
+        haml_tag :a, :href => uri, :'data-ajax' => 'false', :'data-icon' => 'grid' do
+          haml_concat format.to_s.upcase
+        end
+      end
+    end
+
+    def image_for_state(state)
+      state_img = "stopped" if (state!='RUNNING' or state!='PENDING')
+      capture_haml do
+        haml_tag :img, :src => "/images/#{state}" % state.downcase, :title => state
+      end
+    end
+
+    # Reverse the entrypoints hash for a driver from drivers.yaml; note that
+    # +d+ is a hash, not an actual driver object
+    def driver_provider(d)
+      result = {}
+      if d[:entrypoints]
+        d[:entrypoints].each do |kind, details|
+          details.each do |prov, url|
+            result[prov] ||= {}
+            result[prov][kind] = url
+          end
+        end
+      end
+      result
+    end
+
+    def header(title, opts={}, &block)
+      opts[:theme] ||= 'b'
+      opts[:back] ||= 'true'
+      capture_haml do
+        haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme], :'data-add-back-btn' => opts[:back] do
+          haml_tag :a, :'data-rel' => :back do
+            haml_concat "Back"
+          end if opts[:back] == 'true'
+          haml_tag :h1 do
+            haml_concat title
+          end
+          block.call if block_given?
+        end
+      end
+    end
+
+    def subheader(title, opts={})
+      opts[:theme] ||= 'a'
+      capture_haml do
+        haml_tag :div, :'data-role' => :header, :'data-theme' => opts[:theme] do
+          haml_tag :p, :class => 'inner-right' do
+            haml_concat title
+          end
+        end
+      end
+    end
+
+    def translate_error_code(code)
+      case code
+      when 400; { :message => "Bad Request" }
+      when 401; { :message => "Unauthorized" }
+      when 403; { :message => "Forbidden" }
+      when 404; { :message => "Not Found" }
+      when 405; { :message => "Method Not Allowed" }
+      when 406; { :message => "Not Acceptable" }
+      when 500; { :message => "Internal Server Error" }
+      when 502; { :message => "Backend Server Error" }
+      when 501; { :message => "Not Supported" }
+      end
+    end
+
+    def new_blob_form_url(bucket)
+      bucket_url(@bucket.name) + "/" + NEW_BLOB_FORM_ID
+    end
+
+    def format_hardware_property(prop)
+      return "&empty;" unless prop
+      u = hardware_property_unit(prop)
+      case prop.kind
+      when :range
+        "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} #{u})"
+      when :enum
+        prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: #{prop.default} #{u})"
+      else
+        "#{prop.value} #{u}"
+      end
+    end
+
+    def format_instance_profile(ip)
+      o = ip.overrides.collect do |p, v|
+        u = hardware_property_unit(p)
+        "#{p} = #{v} #{u}"
+      end
+      if o.empty?
+        ""
+      else
+        "with #{o.join(", ")}"
+      end
+    end
+
+    private
+    def hardware_property_unit(prop)
+      u = ::Deltacloud::HardwareProfile::unit(prop)
+      u = "" if ["label", "count"].include?(u)
+      u = "vcpus" if prop == :cpu
+      u
+    end
+
+
+
+  end
+end
diff --git a/server/lib/deltacloud/helpers/driver_helper.rb b/server/lib/deltacloud/helpers/driver_helper.rb
new file mode 100644
index 0000000..18e0598
--- /dev/null
+++ b/server/lib/deltacloud/helpers/driver_helper.rb
@@ -0,0 +1,57 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Helpers
+
+  module Drivers
+
+    def driver_symbol
+      driver_name.to_sym
+    end
+
+    def driver_name
+      Thread.current[:driver] ||= ENV['API_DRIVER']
+    end
+
+    def driver_class_name
+      driver_name.camelize
+    end
+
+    def driver_source_name
+      File.join('..', 'drivers', driver_name, driver_name + '_driver.rb')
+    end
+
+    def driver_class
+      begin
+        m = Deltacloud::Drivers.const_get(driver_class_name)
+        m.const_get(driver_class_name + "Driver").new
+      rescue NameError
+        raise "[ERROR] The driver class name is not defined as #{driver_class_name}Driver"
+      end
+    end
+
+    def driver
+      $:.unshift File.join(File.dirname(__FILE__), '..', '..')
+      begin
+        require_relative driver_source_name
+        driver_class
+      rescue LoadError
+        raise "[ERROR] The driver '#{driver_name}' is unknown or not installed" unless valid_driver?
+      end
+    end
+
+  end
+
+end
diff --git a/server/lib/deltacloud/helpers/hardware_profiles_helper.rb b/server/lib/deltacloud/helpers/hardware_profiles_helper.rb
deleted file mode 100644
index 4da9d8c..0000000
--- a/server/lib/deltacloud/helpers/hardware_profiles_helper.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module HardwareProfilesHelper
-
-  def format_hardware_property(prop)
-    return "&empty;" unless prop
-    u = hardware_property_unit(prop)
-    case prop.kind
-      when :range
-      "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} #{u})"
-      when :enum
-      prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: #{prop.default} #{u})"
-      else
-      "#{prop.value} #{u}"
-    end
-  end
-
-  def format_instance_profile(ip)
-    o = ip.overrides.collect do |p, v|
-      u = hardware_property_unit(p)
-      "#{p} = #{v} #{u}"
-    end
-    if o.empty?
-      ""
-    else
-      "with #{o.join(", ")}"
-    end
-  end
-
-  private
-  def hardware_property_unit(prop)
-    u = ::Deltacloud::HardwareProfile::unit(prop)
-    u = "" if ["label", "count"].include?(u)
-    u = "vcpus" if prop == :cpu
-    u
-  end
-end
diff --git a/server/lib/deltacloud/helpers/json_helper.rb b/server/lib/deltacloud/helpers/json_helper.rb
deleted file mode 100644
index aea16b6..0000000
--- a/server/lib/deltacloud/helpers/json_helper.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module JSONHelper
-
-  def json_features_for_entrypoint(entrypoint)
-    features = driver.features(entrypoint.first).collect { |feature| feature.name }
-    features.empty? ? {} : { :features => features }
-  end
-
-  def json_return_error(error)
-    error_output=Hash.new
-    error_output[:url]    =request.env['REQUEST_URI']
-    error_output[:status] =response.status
-    error_output[:message]=error.message if error
-    error_output.to_json
-  end
-
-end
diff --git a/server/lib/deltacloud/helpers/rabbit_helper.rb b/server/lib/deltacloud/helpers/rabbit_helper.rb
new file mode 100644
index 0000000..252abe2
--- /dev/null
+++ b/server/lib/deltacloud/helpers/rabbit_helper.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+Sinatra::Rabbit::Collection.class_eval do
+
+  def self.standard_index_operation
+    collection_name = @collection_name
+    operation :index, :with_capability => collection_name do
+      control { filter_all collection_name }
+    end
+  end
+
+  def self.standard_show_operation
+    collection_name = @collection_name
+    operation :show, :with_capability => collection_name do
+      control { show collection_name.to_s.singularize.intern }
+    end
+  end
+
+end
+
diff --git a/server/lib/deltacloud/helpers/url_helper.rb b/server/lib/deltacloud/helpers/url_helper.rb
new file mode 100644
index 0000000..87bc93e
--- /dev/null
+++ b/server/lib/deltacloud/helpers/url_helper.rb
@@ -0,0 +1,112 @@
+#
+# Based on https://github.com/emk/sinatra-url-for/
+# Commit 1df339284203f8f6ed8d
+#
+# Original license:
+# Copyright (C) 2009 Eric Kidd
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the
+# following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+# USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Sinatra
+  module UrlForHelper
+
+    require 'uri'
+
+    def method_missing(name, *args)
+      if name.to_s =~ /^([\w\_]+)_url$/
+        if args.size > 0
+          t = $1
+          if t =~ /^(stop|reboot|destroy|start|attach|detach)_/
+            api_url_for(t.pluralize.split('_').last + '/' + args.first + '/' + $1, :full)
+          else
+            api_url_for(t.pluralize, :full) + '/' + "#{args.first}"
+          end
+        else
+          api_url_for($1, :full)
+        end
+      else
+        super
+      end
+    end
+
+    def api_url_for(url_fragment, mode=:path_only)
+      matrix_params = ''
+      if request.params['api']
+        matrix_params += ";provider=%s" % request.params['api']['provider'] if request.params['api']['provider']
+        matrix_params += ";driver=%s" % request.params['api']['driver'] if request.params['api']['driver']
+      end
+      url_fragment = "/#{url_fragment}" unless url_fragment =~ /^\// # There is no need to prefix URI with '/'
+      if mode == :path_only
+        url_for "#{settings.root_url}#{matrix_params}#{url_fragment}", mode
+      else
+        url_for "#{matrix_params}#{url_fragment}", :full
+      end
+    end
+
+    # Construct a link to +url_fragment+, which should be given relative to
+    # the base of this Sinatra app.  The mode should be either
+    # <code>:path_only</code>, which will generate an absolute path within
+    # the current domain (the default), or <code>:full</code>, which will
+    # include the site name and port number.  (The latter is typically
+    # necessary for links in RSS feeds.)  Example usage:
+    #
+    #   url_for "/"            # Returns "/myapp/"
+    #   url_for "/foo"         # Returns "/myapp/foo"
+    #   url_for "/foo", :full  # Returns "http://example.com/myapp/foo"
+    #--
+    # See README.rdoc for a list of some of the people who helped me clean
+    # up earlier versions of this code.
+    def url_for url_fragment, mode=:path_only
+      case mode
+      when :path_only
+        base = request.script_name
+      when :full
+        scheme = request.scheme
+        port = request.port
+        request_host = request.host
+        if request.env['HTTP_X_FORWARDED_FOR']
+          scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || scheme
+          port = request.env['HTTP_X_FORWARDED_PORT']
+          request_host = request.env['HTTP_X_FORWARDED_HOST']
+        end
+        if (port.nil? || port == "" ||
+            (scheme == 'http' && port.to_s == '80') ||
+            (scheme == 'https' && port.to_s == '443'))
+          port = ""
+        else
+          port = ":#{port}"
+        end
+        base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
+      else
+        raise TypeError, "Unknown url_for mode #{mode}"
+      end
+      uri_parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
+      url_escape = uri_parser.escape(url_fragment)
+      # Don't add the base fragment if url_for gets called more than once
+      # per url or the url_fragment passed in is an absolute url
+      if url_escape.match(/^#{base}/) or url_escape.match(/^http/)
+        url_escape
+      else
+        "#{base}#{url_escape}"
+      end
+    end
+  end
+
+end
-- 
1.7.10


[PATCH core 05/32] Core: Removed the rack middleware which is not longer needed

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/sinatra/lazy_auth.rb       |   75 ------
 server/lib/sinatra/rabbit.rb          |  441 ---------------------------------
 server/lib/sinatra/rack_cimi.rb       |   33 ---
 server/lib/sinatra/rack_runtime.rb    |   47 ----
 server/lib/sinatra/rack_syslog.rb     |   93 -------
 server/lib/sinatra/sinatra_verbose.rb |   73 ------
 server/lib/sinatra/static_assets.rb   |   99 --------
 server/lib/sinatra/url_for.rb         |   93 -------
 8 files changed, 954 deletions(-)
 delete mode 100644 server/lib/sinatra/lazy_auth.rb
 delete mode 100644 server/lib/sinatra/rabbit.rb
 delete mode 100644 server/lib/sinatra/rack_cimi.rb
 delete mode 100644 server/lib/sinatra/rack_runtime.rb
 delete mode 100644 server/lib/sinatra/rack_syslog.rb
 delete mode 100644 server/lib/sinatra/sinatra_verbose.rb
 delete mode 100644 server/lib/sinatra/static_assets.rb
 delete mode 100644 server/lib/sinatra/url_for.rb

diff --git a/server/lib/sinatra/lazy_auth.rb b/server/lib/sinatra/lazy_auth.rb
deleted file mode 100644
index fb94dd9..0000000
--- a/server/lib/sinatra/lazy_auth.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-
-# Lazy Basic HTTP authentication. Authentication is only forced when the
-# credentials are actually needed.
-module Sinatra
-  module LazyAuth
-    class LazyCredentials
-      def initialize(app)
-        @app = app
-        @provided = false
-      end
-
-      def user
-        credentials!
-        @user
-      end
-
-      def password
-        credentials!
-        @password
-      end
-
-      def provided?
-        @provided
-      end
-
-      private
-      def credentials!
-        if ENV["API_USER"] && ENV["API_PASSWORD"]
-          @user = ENV["API_USER"]
-          @password = ENV["API_PASSWORD"]
-          @provided = true
-        end
-        unless provided?
-          auth = Rack::Auth::Basic::Request.new(@app.request.env)
-          @app.authorize! unless auth.provided? && auth.basic? && auth.credentials
-          @user = auth.credentials[0]
-          @password = auth.credentials[1]
-          @provided = true
-        end
-      end
-
-    end
-
-    def authorize!
-      r = "#{driver_symbol}-deltacloud@#{HOSTNAME}"
-      response['WWW-Authenticate'] = %(Basic realm="#{r}")
-      throw(:halt, [401, report_error(401)])
-    end
-
-    # Request the current user's credentials. Actual credentials are only
-    # requested when an attempt is made to get the user name or password
-    def credentials
-      LazyCredentials.new(self)
-    end
-  end
-
-  helpers LazyAuth
-end
diff --git a/server/lib/sinatra/rabbit.rb b/server/lib/sinatra/rabbit.rb
deleted file mode 100644
index 5c63fd9..0000000
--- a/server/lib/sinatra/rabbit.rb
+++ /dev/null
@@ -1,441 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-require 'sinatra/url_for'
-require 'deltacloud/validation'
-require 'deltacloud/backend_capability'
-
-module Sinatra
-
-  module Rabbit
-
-    def self.routes
-      @routes ||= []
-    end
-
-    class DuplicateParamException < Deltacloud::ExceptionHandler::DeltacloudException; end
-    class DuplicateOperationException < Deltacloud::ExceptionHandler::DeltacloudException; end
-    class DuplicateCollectionException < Deltacloud::ExceptionHandler::DeltacloudException; end
-    class UnsupportedCollectionException < Deltacloud::ExceptionHandler::DeltacloudException
-      def initialize
-        # The server understood the request, but is refusing to fulfill it. Authorization will not help and the request
-        # SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request
-        # has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish
-        # to make this information available to the client, the status code 404 (Not Found) can be used instead.
-        super(403, 'UnsupportedCollection', "Requested collection is not supported for current provider", [])
-      end
-    end
-
-    class Operation
-      attr_reader :name, :method, :collection, :member
-
-      include ::Deltacloud::BackendCapability
-      include ::Deltacloud::Validation
-      include ::ApplicationHelper
-
-      STANDARD = {
-        :new => { :method => :get, :member => false, :form => true },
-        :index => { :method => :get, :member => false },
-        :show =>  { :method => :get, :member => true },
-        :create => { :method => :post, :member => false },
-        :update => { :method => :put, :member => true },
-        :destroy => { :method => :delete, :member => true }
-      }
-
-      def initialize(coll, name, opts, &block)
-        @name = name.to_sym
-        opts = STANDARD[@name].merge(opts) if standard?
-        @path_generator = opts[:path_generator]
-        @collection, @standard = coll, opts[:standard]
-        raise "No method for operation #{name}" unless opts[:method]
-        @method = opts[:method].to_sym
-        @member = opts[:member]
-        @description = ""
-        instance_eval(&block) if block_given?
-        generate_documentation
-        generate_options
-      end
-
-      def http_method
-        @method
-      end
-
-      def standard?
-        STANDARD.keys.include?(name) || @standard
-      end
-
-      def form?
-        STANDARD[name] and STANDARD[name][:form]
-      end
-
-      def description(text="")
-        return @description if text.blank?
-        @description = text
-      end
-
-      def generate_documentation
-        coll, oper = @collection, self
-        Rabbit::routes << [:get, "#{settings.root_url}/docs/#{@collection.name}/#{@name}"]
-        ::Sinatra::Application.get("#{settings.root_url}/docs/#{@collection.name}/#{@name}") do
-          @collection, @operation = coll, oper
-          @features = driver.features_for_operation(coll.name, oper.name)
-          respond_to do |format|
-            format.html { haml :'docs/operation' }
-            format.xml { haml :'docs/operation' }
-          end
-        end
-      end
-
-      def generate_options
-        current_operation = self
-        Rabbit::routes << [:options, "#{settings.root_url}/#{current_operation.collection.name}/#{current_operation.name}"]
-        ::Sinatra::Application.options("#{settings.root_url}/#{current_operation.collection.name}/#{current_operation.name}") do
-          required_params = current_operation.effective_params(driver).collect do |name, validation|
-            name.to_s if validation.type.eql?(:required)
-          end.compact.join(',')
-          optional_params = current_operation.effective_params(driver).collect do |name, validation|
-            name.to_s if validation.type.eql?(:optional)
-          end.compact.join(',')
-          headers 'X-Required-Parameters' => required_params
-          headers 'X-Optional-Parameters' => optional_params
-          [200, '']
-        end
-      end
-
-      def control(&block)
-        op = self
-        @control = Proc.new do
-          op.collection.check_supported(driver)
-          op.check_capability(driver)
-          op.validate(driver, op.effective_params(driver), params, credentials)
-          instance_eval(&block)
-        end
-      end
-
-      def member?
-        if standard?
-          @member || STANDARD[name][:member]
-        else
-          @member
-        end
-      end
-
-      def path(args = {})
-        return @path_generator.call(self) if @path_generator
-        if member?
-          if standard?
-            "#{@collection.name}/:id"
-          else
-            "#{@collection.name}/:id/#{name}"
-          end
-        else
-          if form?
-            "#{@collection.name}/#{name}"
-          else
-            "#{@collection.name}"
-          end
-        end
-      end
-
-      def generate
-        Rabbit::routes << [@method, "#{settings.root_url}/#{path}"]
-        ::Sinatra::Application.send(@method, "#{settings.root_url}/#{path}", {}, &@control)
-        # Set up some Rails-like URL helpers
-        if name == :index
-          gen_route "#{@collection.name}_url"
-        elsif name == :show
-          gen_route "#{@collection.name.to_s.singularize}_url"
-        else
-          gen_route "#{name}_#{@collection.name.to_s.singularize}_url"
-        end
-      end
-
-      # Return a hash of all params, the params statically defined for this
-      # operation plus the params defined by any features in the +driver+
-      # that might modify this operation
-      def effective_params(driver)
-        driver.features(@collection.name).collect do |f|
-          f.decl.operation(@name)
-        end.flatten.select { |op| op }.inject(params.dup) do |result, fop|
-          fop.params.each_key do |k|
-            if result.has_key?(k)
-              raise DuplicateParamException, "Parameter '#{k}' for operation #{fop.name} in collection #{@collection.name}"
-            else
-              result[k] = fop.params[k]
-            end
-          end
-          result
-        end
-      end
-
-      private
-      def gen_route(name)
-        route_url = path
-        if @member
-          ::Sinatra::Application.send(:define_method, name) do |id, *args|
-            url = query_url(route_url, args[0])
-            api_url_for url.gsub(/:id/, id.to_s), :full
-          end
-        else
-          ::Sinatra::Application.send(:define_method, name) do |*args|
-            url = query_url(route_url, args[0])
-            api_url_for url, :full
-          end
-        end
-      end
-    end
-
-    class Collection
-      attr_reader :name, :operations, :subcollections
-
-      def initialize(name, options={}, &block)
-        @name = name
-        @description = ""
-        @operations, @subcollections = {}, {}
-        @global = options[:global] || false
-        instance_eval(&block) if block_given?
-        generate_documentation
-        generate_head
-        generate_options
-      end
-
-      def subcollection?
-        self.class == SubCollection
-      end
-
-      # Set/Return description for collection
-      # If first parameter is not present, full description will be
-      # returned.
-      def description(text='')
-        return @description if text.blank?
-        @description = text
-      end
-
-      # Mark this collection as global, i.e. independent of any specific
-      # driver
-      def global!
-        @global = true
-      end
-
-      # Return +true+ if this collection is global, i.e. independent of any
-      # specific driver
-      def global?
-        @global
-      end
-
-      def generate_head
-        current_collection = self
-        Rabbit::routes << [:head, "#{settings.root_url}/#{name}"]
-        ::Sinatra::Application.head("#{settings.root_url}/#{name}") do
-          methods_allowed = current_collection.operations.collect { |o| o[1].method.to_s.upcase }.uniq.join(',')
-          headers 'Allow' => "HEAD,OPTIONS,#{methods_allowed}"
-          [200, '']
-        end
-      end
-
-      def generate_options
-        current_collection = self
-        Rabbit::routes << [:options, "#{settings.root_url}/#{name}"]
-        ::Sinatra::Application.options("#{settings.root_url}/#{name}") do
-          operations_allowed = current_collection.operations.collect { |o| o[0] }.join(',')
-          headers 'X-Operations-Allowed' => operations_allowed
-          [200, '']
-        end
-      end
-
-      def generate_documentation
-        coll = self
-        Rabbit::routes << [:get, "#{settings.root_url}/docs/#{@name}"]
-        ::Sinatra::Application.get("#{settings.root_url}/docs/#{@name}") do
-          coll.check_supported(driver)
-          @collection = coll
-          @operations = coll.operations
-          @features = driver.features(coll.name)
-          respond_to do |format|
-            format.html { haml :'docs/collection' }
-            format.xml { haml :'docs/collection' }
-          end
-        end
-      end
-
-      # Add a new operation for this collection. For the standard REST
-      # operations :index, :show, :update, and :destroy, we already know
-      # what method to use and whether this is an operation on the URL for
-      # individual elements or for the whole collection.
-      #
-      # For non-standard operations, options must be passed:
-      #  :method : one of the HTTP methods
-      #  :member : whether this is an operation on the collection or an
-      #            individual element (FIXME: custom operations on the
-      #            collection will use a nonsensical URL) The URL for the
-      #            operation is the element URL with the name of the operation
-      #            appended
-      #
-      # This also defines a helper method like show_instance_url that returns
-      # the URL to this operation (in request context)
-      def operation(name, opts = {}, &block)
-        if @operations.keys.include?(name)
-          raise DuplicateOperationException::new(500, "DuplicateOperation", "Operation #{name} is already defined", [])
-        end
-        @operations[name] = Operation.new(self, name, opts, &block)
-      end
-
-      def collection(name, opts={}, &block)
-        if subcollections.keys.include?(name)
-          raise DuplicateOperationException::new(500, "DuplicateSubcollection", "Subcollection #{name} is already defined", [])
-        end
-        subcollections[name] = SubCollection.new(self, name, opts, &block)
-        subcollections[name].generate
-      end
-
-      def generate
-        operations.values.reject { |op| op.member }.each { |o| o.generate }
-        operations.values.select { |op| op.member }.each { |o| o.generate }
-        app = ::Sinatra::Application
-        collname = name # Work around Ruby's weird scoping/capture
-        app.send(:define_method, "#{name.to_s.singularize}_url") do |id|
-          api_url_for "#{collname}/#{id}", :full
-        end
-        if index_op = operations[:index]
-          app.send(:define_method, "#{name}_url") do
-            api_url_for index_op.path.gsub(/\/\?$/,''), :full
-          end
-        end
-      end
-
-      def check_supported(driver)
-        unless global? || driver.has_collection?(@name) || self.kind_of?(Sinatra::Rabbit::SubCollection)
-          raise UnsupportedCollectionException
-        end
-      end
-    end
-
-    class SubCollection < Collection
-
-      attr_accessor :parent
-
-      def initialize(parent, name, opts={}, &block)
-        self.parent = parent
-        super(name, &block)
-      end
-
-      def operation(name, opts = {}, &block)
-        if @operations.keys.include?(name)
-          raise DuplicateOperationException::new(500, "DuplicateOperation", "Operation #{name} is already defined", [])
-        end
-        # Preserve self as local variable to workaround Ruby namespace
-        # weirdness
-        c = self
-        path_generator = Proc.new do |obj|
-          if obj.member?
-            if obj.standard?
-              "#{parent.name}/:#{parent.name.to_s.singularize}/:#{c.name.to_s.singularize}"
-            else
-              "#{parent.name}/:#{parent.name.to_s.singularize}/:#{c.name.to_s.singularize}/#{name}"
-            end
-          else
-            if obj.form?
-              "#{parent.name}/:id/:#{parent.name.to_s.singularize}/#{obj.name}"
-            else
-              "#{parent.name}/:#{parent.name.to_s.singularize}"
-            end
-          end
-        end
-        opts.merge!({
-          :path_generator => path_generator
-        })
-        @operations[name] = Operation.new(self, name, opts, &block)
-      end
-
-      def generate
-        operations.values.reject { |op| op.member }.each { |o| o.generate }
-        operations.values.select { |op| op.member }.each { |o| o.generate }
-        app = ::Sinatra::Application
-        collname = name # Work around Ruby's weird scoping/capture
-        app.send(:define_method, "#{parent.name.to_s}_#{name.to_s.singularize}_url") do |id, subid|
-          api_url_for "#{collname}/#{id}/#{subid}", :full
-        end
-        if index_op = operations[:index]
-          app.send(:define_method, "#{parent.name.to_s}_#{name}_url") do
-            api_url_for index_op.path.gsub(/\/\?$/,''), :full
-          end
-        end
-      end
-
-    end
-
-    def collections
-      @collections ||= {}
-    end
-
-    # Create a new collection. NAME should be the pluralized name of the
-    # collection.
-    #
-    # Adds a helper method #{name}_url which returns the URL to the :index
-    # operation on this collection.
-    def collection(name, &block)
-      raise DuplicateCollectionException if collections[name]
-      collections[name] = Collection.new(name, &block)
-      collections[name].generate
-    end
-
-    def global_collection(name, &block)
-      raise DuplicateCollectionException if collections[name]
-      collections[name] = Collection.new(name, { :global => true }, &block)
-      collections[name].generate
-    end
-
-    # Make sure this collection can be accessed, regardless of whether the
-    # driver supports it or not
-    def global_collection(name, &block)
-      raise DuplicateCollectionException if collections[name]
-      collections[name] = Collection.new(name, :global => true, &block)
-      collections[name].generate
-    end
-  end
-
-  module RabbitHelper
-    def query_url(url, params)
-      return url if params.nil? || params.empty?
-      url + "?#{URI.escape(params.collect{|k,v| "#{k}=#{v}"}.join('&'))}"
-    end
-
-    def entry_points
-      collections.values.select { |coll|
-        coll.global? || driver.has_collection?(coll.name)
-      }.inject([]) do |m, coll|
-        url = api_url_for coll.operations[:index].path, :full
-        m << [ coll.name, url ]
-      end
-    end
-  end
-
-  register Rabbit
-  helpers RabbitHelper
-end
-
-# In Sinatra < 1.2 there was no helper to create OPTIONS route
-unless Sinatra::Base.respond_to? :options
-  configure do
-    class << Sinatra::Base
-      def options(path, opts={}, &block)
-        route 'OPTIONS', path, opts, &block
-      end
-    end
-    Sinatra::Delegator.delegate :options
-  end
-end
diff --git a/server/lib/sinatra/rack_cimi.rb b/server/lib/sinatra/rack_cimi.rb
deleted file mode 100644
index 6d5ea78..0000000
--- a/server/lib/sinatra/rack_cimi.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Rack
-  # Automatically sets the X-CIMI-Specification-Version header on all responses.
-  #
-  class CIMI
-
-    def initialize(app, no_cache_control = nil, cache_control = nil)
-      @app = app
-    end
-
-    def call(env)
-      status, headers, body = @app.call(env)
-      headers['X-CIMI-Specification-Version'] = '0.0.66'
-      [status, headers, body]
-    end
-
-  end
-end
-
diff --git a/server/lib/sinatra/rack_runtime.rb b/server/lib/sinatra/rack_runtime.rb
deleted file mode 100644
index dc56fc7..0000000
--- a/server/lib/sinatra/rack_runtime.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (c) 2008 The Committers
-
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-module Rack
-  # Sets an "X-Runtime" response header, indicating the response
-  # time of the request, in seconds
-  #
-  # You can put it right before the application to see the processing
-  # time, or before all the other middlewares to include time for them,
-  # too.
-  class Runtime
-    def initialize(app, name = nil)
-      @app = app
-      @header_name = "X-Runtime"
-      @header_name << "-#{name}" if name
-    end
-
-    def call(env)
-      start_time = Time.now
-      status, headers, body = @app.call(env)
-      request_time = Time.now - start_time
-
-      if !headers.has_key?(@header_name)
-        headers[@header_name] = "%0.6f" % request_time
-      end
-
-      [status, headers, body]
-    end
-  end
-end
-
diff --git a/server/lib/sinatra/rack_syslog.rb b/server/lib/sinatra/rack_syslog.rb
deleted file mode 100644
index 5565179..0000000
--- a/server/lib/sinatra/rack_syslog.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-begin
-  require 'syslog'
-  USE_SYSLOG = true
-rescue LoadError => e
-  USE_SYSLOG = false
-end
-
-require 'sinatra/body_proxy'
-
-class SyslogFile < File
-
-  def initialize
-    @log = USE_SYSLOG ? Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_LOCAL5) : Logger.new(STDOUT)
-  end
-
-  def write(string)
-    @log.warning(string) if string.strip.length > 0
-    return string.chars.count
-  end
-
-  def info(msg)
-    @log.info("%s" % msg)
-  end
-
-  def err(msg)
-    @log.err("%s" % msg)
-  end
-
-  alias :warning :err
-
-end
-
-# Code bellow was originaly copied from Rack::CommonLogger
-# https://raw.github.com/rack/rack/master/lib/rack/commonlogger.rb
-
-module Rack
-  # Rack::CommonLogger forwards every request to an +app+ given, and
-  # logs a line in the Apache common log format to the +logger+, or
-  # rack.errors by default.
-  class SyslogLogger
-
-    # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
-    # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
-    #             %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
-    FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f}
-
-    def initialize(app, logger=nil)
-      @app = app
-      @logger = logger || @app.settings.logger || $stdout
-    end
-
-    def call(env)
-      began_at = Time.now
-      status, header, body = @app.call(env)
-      header = Utils::HeaderHash.new(header)
-      body = Rack::BodyProxy.new(body) do
-        log(env, status, header, began_at)
-      end
-      body.close
-      [status, header, body]
-    end
-
-    def log(env, status, header, began_at)
-      now = Time.now
-      length = extract_content_length(header)
-
-      if status.to_s =~ /5(\d{2})/
-        method = :err
-      else
-        method = :info
-      end
-
-      logger = @logger
-      logger.send(method, FORMAT % [
-        env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
-        env["REMOTE_USER"] || "-",
-        now.strftime("%d/%b/%Y %H:%M:%S"),
-        env["REQUEST_METHOD"],
-        env["PATH_INFO"],
-        env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
-        env["HTTP_VERSION"],
-        status.to_s[0..3],
-        length,
-        now - began_at ])
-    end
-
-    def extract_content_length(headers)
-      value = headers['Content-Length'] or return '-'
-      value.to_s == '0' ? '-' : value
-    end
-  end
-end
-
diff --git a/server/lib/sinatra/sinatra_verbose.rb b/server/lib/sinatra/sinatra_verbose.rb
deleted file mode 100644
index c016ec0..0000000
--- a/server/lib/sinatra/sinatra_verbose.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-
-module Sinatra
-  module VerboseLogger
-
-    module Helpers
-
-      def info(message)
-        puts sprintf("\033[1;34m[INFO: #{caller_method_name}]\033[0m: %s", message.inspect)
-      end
-
-      alias :debug :info
-
-      def warn(message)
-        puts sprintf("\033[1;31m[WARN: #{caller_method_name}]\033[0m: %s", message.inspect)
-      end
-
-      private
-
-      def caller_method_name
-        caller(2).first
-      end
-
-    end
-
-    def enable_verbose_logging!
-      disable :logging
-      before {
-        puts sprintf("\n\033[1;29mProcessing %s\033[0m (for %s at #{Time.now}) [%s] [\033[1;29m%s\033[0m]",
-                     request.path_info, request.ip, request.request_method, driver_name)
-        puts "Parameters: #{params.inspect}"
-        if provider=Thread::current[:provider] || ENV['API_PROVIDER']
-          puts "Provider: #{provider}"
-        end
-        puts "Authentication: #{request.env['HTTP_AUTHORIZATION'].split(' ').first}" if request.env['HTTP_AUTHORIZATION']
-        puts "Server: #{request.env['SERVER_SOFTWARE']}"
-        puts "Accept: #{request.env['HTTP_ACCEPT']}"
-        puts
-      }
-      after {
-        puts sprintf("\nCompleted in \033[1;29m%4f\033[0m | %4f | %s | \033[1;36m%s\033[0m | %s\n",
-                     response.header['X-Backend-Runtime'] || 0, response.header['X-Runtime'] || 0, response.status, response.content_type, request.url)
-      }
-    end
-
-    def self.registered(app)
-      app.helpers VerboseLogger::Helpers
-      app.enable_verbose_logging! if ENV['API_VERBOSE']
-    end
-  end
-end
-
-Sinatra::Application.register Sinatra::VerboseLogger
-
-Deltacloud::BaseDriver.class_eval do
-  include Sinatra::VerboseLogger::Helpers
-end
diff --git a/server/lib/sinatra/static_assets.rb b/server/lib/sinatra/static_assets.rb
deleted file mode 100644
index 5233965..0000000
--- a/server/lib/sinatra/static_assets.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'sinatra/base'
-require 'sinatra/url_for'
-
-module Sinatra
-  module StaticAssets
-    module Helpers
-      # In HTML <link> and <img> tags have no end tag.
-      # In XHTML, on the contrary, these tags must be properly closed.
-      #
-      # We can choose the appropriate behaviour with +closed+ option:
-      #
-      #   image_tag "/images/foo.png", :alt => "Foo itself", :closed => true
-      #
-      # The default value of +closed+ option is +false+.
-      #
-      def image_tag(source, options = {})
-        options[:src] = url_for(source)
-        tag("img", options)
-      end
-
-      def stylesheet_link_tag(*sources)
-        list, options = extract_options(sources)
-        list.collect { |source| stylesheet_tag(source, options) }.join("\n")
-      end
-
-      def javascript_script_tag(*sources)
-        list, options = extract_options(sources)
-        list.collect { |source| javascript_tag(source, options) }.join("\n")
-      end
-
-      def link_to(desc, url, options = {})
-        tag("a", options.merge(:href => url_for(url))) do
-          desc
-        end
-      end
-
-      private
-
-      def tag(name, local_options = {})
-        start_tag = "<#{name}#{tag_options(local_options) if local_options}"
-        if block_given?
-          content = yield
-          "#{start_tag}>#{content}</#{name}>"
-        else
-          "#{start_tag}#{"/" if settings.xhtml}>"
-        end
-      end
-
-      def tag_options(options)
-        unless options.empty?
-          attrs = []
-          attrs = options.map { |key, value| %(#{key}="#{Rack::Utils.escape_html(value)}") }
-          " #{attrs.sort * ' '}" unless attrs.empty?
-        end
-      end
-
-      def stylesheet_tag(source, options = {})
-        tag("link", { :type => "text/css",
-            :charset => "utf-8", :media => "screen", :rel => "stylesheet",
-            :href => url_for(source) }.merge(options))
-      end
-
-      def javascript_tag(source, options = {})
-        tag("script", { :type => "text/javascript", :charset => "utf-8",
-            :src => url_for(source) }.merge(options)) do
-            end
-      end
-
-      def extract_options(a)
-        opts = a.last.is_a?(::Hash) ? a.pop : {}
-        [a, opts]
-      end
-
-    end
-
-    def self.registered(app)
-      app.helpers StaticAssets::Helpers
-      app.disable :xhtml
-    end
-  end
-
-  register StaticAssets
-end
diff --git a/server/lib/sinatra/url_for.rb b/server/lib/sinatra/url_for.rb
deleted file mode 100644
index fba6668..0000000
--- a/server/lib/sinatra/url_for.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-#
-# Based on https://github.com/emk/sinatra-url-for/
-# Commit 1df339284203f8f6ed8d
-#
-# Original license:
-# Copyright (C) 2009 Eric Kidd
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the
-# following conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
-# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-# USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-require 'uri'
-
-module Sinatra
-  module UrlForHelper
-
-    def api_url_for(url_fragment, mode=:path_only)
-      matrix_params = ''
-      if request.params['api']
-        matrix_params += ";provider=%s" % request.params['api']['provider'] if request.params['api']['provider']
-        matrix_params += ";driver=%s" % request.params['api']['driver'] if request.params['api']['driver']
-      end
-      url_fragment = "/#{url_fragment}" unless url_fragment =~ /^\// # There is no need to prefix URI with '/'
-      url_for "#{settings.root_url}#{matrix_params}#{url_fragment}", mode
-    end
-
-    # Construct a link to +url_fragment+, which should be given relative to
-    # the base of this Sinatra app.  The mode should be either
-    # <code>:path_only</code>, which will generate an absolute path within
-    # the current domain (the default), or <code>:full</code>, which will
-    # include the site name and port number.  (The latter is typically
-    # necessary for links in RSS feeds.)  Example usage:
-    #
-    #   url_for "/"            # Returns "/myapp/"
-    #   url_for "/foo"         # Returns "/myapp/foo"
-    #   url_for "/foo", :full  # Returns "http://example.com/myapp/foo"
-    #--
-    # See README.rdoc for a list of some of the people who helped me clean
-    # up earlier versions of this code.
-    def url_for url_fragment, mode=:path_only
-      case mode
-      when :path_only
-        base = request.script_name
-      when :full
-        scheme = request.scheme
-        port = request.port
-        request_host = request.host
-        if request.env['HTTP_X_FORWARDED_FOR']
-          scheme = request.env['HTTP_X_FORWARDED_SCHEME'] || scheme
-          port = request.env['HTTP_X_FORWARDED_PORT']
-          request_host = request.env['HTTP_X_FORWARDED_HOST']
-        end
-        if (port.nil? || port == "" ||
-            (scheme == 'http' && port.to_s == '80') ||
-            (scheme == 'https' && port.to_s == '443'))
-          port = ""
-        else
-          port = ":#{port}"
-        end
-        base = "#{scheme}://#{request_host}#{port}#{request.script_name}"
-      else
-        raise TypeError, "Unknown url_for mode #{mode}"
-      end
-      url_escape = URI.escape(url_fragment)
-      # Don't add the base fragment if url_for gets called more than once
-      # per url or the url_fragment passed in is an absolute url
-      if url_escape.match(/^#{base}/) or url_escape.match(/^http/)
-        url_escape
-      else
-        "#{base}#{url_escape}"
-      end
-    end
-  end
-
-
-
-  helpers UrlForHelper
-end
-- 
1.7.10


[PATCH core 11/32] Core: Moved base_driver and exception handling API to drivers directory

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 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/drivers/base_driver.rb     |  265 +++++++++++++++++++++
 server/lib/deltacloud/drivers/exceptions.rb      |  191 +++++++++++++++
 5 files changed, 456 insertions(+), 717 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/drivers/base_driver.rb
 create mode 100644 server/lib/deltacloud/drivers/exceptions.rb

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


[PATCH core 32/32] Core: Added Minitest suite to test API abilities

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/tests/drivers/api/api_test.rb               |  115 +++++++
 server/tests/drivers/api/buckets_test.rb           |  194 +++++++++++
 server/tests/drivers/api/common.rb                 |   58 ++++
 server/tests/drivers/api/drivers_test.rb           |  120 +++++++
 server/tests/drivers/api/hardware_profiles_test.rb |  221 +++++++++++++
 server/tests/drivers/api/images_test.rb            |  194 +++++++++++
 server/tests/drivers/api/instances_test.rb         |  340 ++++++++++++++++++++
 server/tests/drivers/api/keys_test.rb              |  158 +++++++++
 server/tests/drivers/api/realms_test.rb            |  129 ++++++++
 server/tests/drivers/api/storage_snapshots_test.rb |  111 +++++++
 server/tests/drivers/api/storage_volumes_test.rb   |  119 +++++++
 11 files changed, 1759 insertions(+)
 create mode 100644 server/tests/drivers/api/api_test.rb
 create mode 100644 server/tests/drivers/api/buckets_test.rb
 create mode 100644 server/tests/drivers/api/common.rb
 create mode 100644 server/tests/drivers/api/drivers_test.rb
 create mode 100644 server/tests/drivers/api/hardware_profiles_test.rb
 create mode 100644 server/tests/drivers/api/images_test.rb
 create mode 100644 server/tests/drivers/api/instances_test.rb
 create mode 100644 server/tests/drivers/api/keys_test.rb
 create mode 100644 server/tests/drivers/api/realms_test.rb
 create mode 100644 server/tests/drivers/api/storage_snapshots_test.rb
 create mode 100644 server/tests/drivers/api/storage_volumes_test.rb

diff --git a/server/tests/drivers/api/api_test.rb b/server/tests/drivers/api/api_test.rb
new file mode 100644
index 0000000..3308365
--- /dev/null
+++ b/server/tests/drivers/api/api_test.rb
@@ -0,0 +1,115 @@
+describe 'Deltacloud API' do
+  include Deltacloud::Test
+
+  it 'return HTTP_OK when accessing API entrypoint' do
+    get API_ROOT_URL
+    last_response.status.must_equal 200
+  end
+
+  it 'advertise the current driver in API entrypoint' do
+    get API_ROOT_URL
+    xml_response.root[:driver].must_equal ENV['API_DRIVER']
+  end
+
+  it 'advertise the current API version in API entrypoint' do
+    get API_ROOT_URL
+    xml_response.root[:version].must_equal API_VERSION
+  end
+
+  it 'advertise the current API version in HTTP headers' do
+    get API_ROOT_URL
+    last_response.headers['Server'].must_equal "Apache-Deltacloud/#{API_VERSION}"
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    get API_ROOT_URL
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'advertise collections in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link').wont_be_empty
+  end
+
+  it 'include the :href and :rel attribute for each collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link').each do |collection|
+      collection[:href].wont_be_nil
+      collection[:rel].wont_be_nil
+    end
+  end
+
+  it 'uses the absolute URI in the :href attribute for each collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link').each do |collection|
+      collection[:href].must_match /^http/
+    end
+  end
+
+  it 'advertise features for some collections in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link/feature').wont_be_empty
+  end
+
+  it 'advertise the name of the feature for some collections in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link/feature').each do |f|
+      f[:name].wont_be_nil
+    end
+  end
+
+  it 'must change the media type from XML to JSON using Accept headers' do
+    header 'Accept', 'application/json'
+    get API_ROOT_URL
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must change the media type to JSON using the "?format" parameter in URL' do
+    get API_ROOT_URL, { :format => 'json' }
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must change the driver when using X-Deltacloud-Driver HTTP header' do
+    header 'X-Deltacloud-Driver', 'ec2'
+    get API_ROOT_URL
+    xml_response.root[:driver].must_equal 'ec2'
+    header 'X-Deltacloud-Driver', 'mock'
+    get API_ROOT_URL
+    xml_response.root[:driver].must_equal 'mock'
+  end
+
+  it 'must change the features when driver is swapped using HTTP headers' do
+    header 'X-Deltacloud-Driver', 'ec2'
+    get API_ROOT_URL
+    # The 'user_name' feature is not supported currently for the EC2 driver
+    (xml_response/'api/link/feature').map { |f| f[:name] }.wont_include 'user_name'
+    header 'X-Deltacloud-Driver', 'mock'
+    get API_ROOT_URL
+    # But it's supported in Mock driver
+    (xml_response/'api/link/feature').map { |f| f[:name] }.must_include 'user_name'
+  end
+
+  it 'must re-validate the driver credentials when using "?force_auth" parameter in URL' do
+    get API_ROOT_URL, { :force_auth => '1' }
+    last_response.status.must_equal 401
+    auth_as_mock
+    get API_ROOT_URL, { :force_auth => '1' }
+    last_response.status.must_equal 200
+  end
+
+  it 'must change the API PROVIDER using the /api;provider matrix parameter in URI' do
+    get API_ROOT_URL + ';provider=test1'
+    xml_response.root[:provider].wont_be_nil
+    xml_response.root[:provider].must_equal 'test1'
+    get API_ROOT_URL + ';provider=test2'
+    xml_response.root[:provider].must_equal 'test2'
+  end
+
+  it 'must change the API DRIVER using the /api;driver matrix parameter in URI' do
+    get API_ROOT_URL + ';driver=ec2'
+    xml_response.root[:driver].must_equal 'ec2'
+    get API_ROOT_URL + ';driver=mock'
+    xml_response.root[:driver].must_equal 'mock'
+  end
+
+end
diff --git a/server/tests/drivers/api/buckets_test.rb b/server/tests/drivers/api/buckets_test.rb
new file mode 100644
index 0000000..47b8007
--- /dev/null
+++ b/server/tests/drivers/api/buckets_test.rb
@@ -0,0 +1,194 @@
+describe 'Deltacloud API buckets' do
+  include Deltacloud::Test
+
+  it 'must advertise have the buckets collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=buckets]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "bucket" collection' do
+    get collection_url(:buckets)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :buckets collection with authentication' do
+    auth_as_mock
+    get collection_url(:buckets)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:buckets)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:buckets)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "buckets" element on top level' do
+    auth_as_mock
+    get collection_url(:buckets)
+    xml_response.root.name.must_equal 'buckets'
+  end
+
+  it 'must have some "bucket" elements inside "buckets"' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each bucket in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "bucket" element in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the bucket' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:buckets) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each bucket in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      (r/'name').wont_be_nil
+    end
+  end
+
+  it 'must have the "state" element defined for each bucket in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      (r/'state').wont_be_nil
+    end
+  end
+
+  it 'must return the full "bucket" when following the URL in bucket element' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the bucket and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "size" element for the bucket and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'size').wont_be_empty
+      (xml_response/'size').first.text.must_equal((r/'size').first.text)
+    end
+  end
+
+  it 'must have the "blob" elements for the bucket and it should match with the ones in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'bucket/blob').wont_be_empty
+      (xml_response/'bucket/blob').size.to_s.must_equal (xml_response/'size').first.text
+      (xml_response/'bucket/blob').each do |b|
+        b[:id].wont_be_nil
+        b[:href].wont_be_nil
+        b[:href].must_match /^http/
+        b[:href].must_match /#{r[:id]}\/#{b[:id]}$/
+      end
+    end
+  end
+
+  it 'must have the "blob" elements for the bucket and it should match with the ones in collection' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'bucket/blob').wont_be_empty
+      (xml_response/'bucket/blob').size.to_s.must_equal (xml_response/'size').first.text
+      (xml_response/'bucket/blob').each do |b|
+        b[:id].wont_be_nil
+        b[:href].wont_be_nil
+        b[:href].must_match /^http/
+        b[:href].must_match /#{r[:id]}\/#{b[:id]}$/
+      end
+    end
+  end
+
+  it 'must allow to get all blobs details and the details should be set correctly' do
+    auth_as_mock
+    get collection_url(:buckets)
+    (xml_response/'buckets/bucket').each do |r|
+      get collection_url(:buckets) + '/' + r[:id]
+      (xml_response/'bucket/blob').each do |b|
+        get collection_url(:buckets) + '/' + r[:id] + '/' + b[:id]
+        xml_response.root.name.must_equal 'blob'
+        xml_response.root[:id].must_equal b[:id]
+        (xml_response/'bucket').wont_be_empty
+        (xml_response/'bucket').size.must_equal 1
+        (xml_response/'bucket').first[:id].wont_be_nil
+        (xml_response/'bucket').first[:href].wont_be_nil
+        (xml_response/'content_length').wont_be_empty
+        (xml_response/'content_length').size.must_equal 1
+        (xml_response/'content_length').first.text.must_match /^(\d+)$/
+        (xml_response/'content_type').wont_be_empty
+        (xml_response/'content_type').size.must_equal 1
+        (xml_response/'content_type').first.text.wont_be_empty
+        (xml_response/'last_modified').wont_be_empty
+        (xml_response/'last_modified').size.must_equal 1
+        (xml_response/'last_modified').first.text.wont_be_empty
+        (xml_response/'content').wont_be_empty
+        (xml_response/'content').size.must_equal 1
+        (xml_response/'content').first[:rel].wont_be_nil
+        (xml_response/'content').first[:rel].must_equal 'blob_content'
+        (xml_response/'content').first[:href].wont_be_nil
+        (xml_response/'content').first[:href].must_match /^http/
+        (xml_response/'content').first[:href].must_match /\/content$/
+      end
+    end
+  end
+
+end
diff --git a/server/tests/drivers/api/common.rb b/server/tests/drivers/api/common.rb
new file mode 100644
index 0000000..a45c1f4
--- /dev/null
+++ b/server/tests/drivers/api/common.rb
@@ -0,0 +1,58 @@
+unless Kernel.respond_to?(:require_relative)
+  module Kernel
+    def require_relative(path)
+      require File.join(File.dirname(caller[0]), path.to_str)
+    end
+  end
+end
+
+API_ROOT_URL = "/api" unless defined?(API_ROOT_URL)
+API_VERSION = "1.0.0" unless defined?(API_VERSION)
+ENV['API_DRIVER'] ||= 'mock'
+
+ENV['API_USERNAME'] ||= 'mockuser'
+ENV['API_PASSWORD'] ||= 'mockpassword'
+
+require_relative '../../lib/deltacloud/server.rb'
+
+require 'minitest/autorun'
+require 'rack/test'
+require 'nokogiri'
+require 'json'
+
+require 'pp'
+
+module Deltacloud
+  module Test
+    include Rack::Test::Methods
+
+    def included?(sub)
+      sub.class_eval do
+        before do
+          header 'Accept', 'application/xml'
+        end
+      end
+    end
+
+    def xml_response
+      Nokogiri::XML(last_response.body)
+    end
+
+    def auth_as_mock
+      authorize ENV['API_USERNAME'], ENV['API_PASSWORD']
+    end
+
+    def collection_url(collection)
+      [API_ROOT_URL, collection.to_s].join('/')
+    end
+
+    def app
+      Rack::Builder.new {
+        map '/' do
+          use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+          run Rack::Cascade.new([Deltacloud::API])
+        end
+      }
+    end
+  end
+end
diff --git a/server/tests/drivers/api/drivers_test.rb b/server/tests/drivers/api/drivers_test.rb
new file mode 100644
index 0000000..41c2e66
--- /dev/null
+++ b/server/tests/drivers/api/drivers_test.rb
@@ -0,0 +1,120 @@
+describe 'Deltacloud API drivers' do
+  include Deltacloud::Test
+
+  it 'must advertise have the drivers collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=drivers]').wont_be_empty
+  end
+
+  it 'must not require authentication to access the "driver" collection' do
+    get collection_url(:drivers)
+    last_response.status.must_equal 200
+  end
+
+  it 'should respond with HTTP_OK when accessing the :drivers collection with authentication' do
+    get collection_url(:drivers)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    header 'Accept', 'application/json'
+    get collection_url(:drivers)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    get collection_url(:drivers)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "drivers" element on top level' do
+    get collection_url(:drivers)
+    xml_response.root.name.must_equal 'drivers'
+  end
+
+  it 'must have some "driver" elements inside "drivers"' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each driver in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "driver" element in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the driver' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    options collection_url(:drivers) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each driver in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      (r/'name').wont_be_nil
+    end
+  end
+
+
+  it 'must return the full "driver" when following the URL in driver element' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      get collection_url(:drivers) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the driver and it should match with the one in collection' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver').each do |r|
+      get collection_url(:drivers) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'should advertise available providers for some drivers' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver/provider').each do |p|
+      p[:id].wont_be_nil
+    end
+  end
+
+  it 'should expose entrypoints for each provider if driver has providers defined' do
+    get collection_url(:drivers)
+    (xml_response/'drivers/driver/provider').each do |p|
+      get collection_url(:drivers) + '/' + p.parent[:id]
+      (xml_response/"driver/provider[@id=#{p[:id]}]").wont_be_empty
+      (xml_response/"driver/provider[@id=#{p[:id]}]").size.must_equal 1
+      (xml_response/"driver/provider[@id=#{p[:id]}]/entrypoint").wont_be_empty
+      (xml_response/"driver/provider[@id=#{p[:id]}]/entrypoint").each do |e|
+        e[:kind].wont_be_nil
+        e.text.wont_be_empty
+      end
+    end
+  end
+
+end
diff --git a/server/tests/drivers/api/hardware_profiles_test.rb b/server/tests/drivers/api/hardware_profiles_test.rb
new file mode 100644
index 0000000..3dad5a8
--- /dev/null
+++ b/server/tests/drivers/api/hardware_profiles_test.rb
@@ -0,0 +1,221 @@
+describe 'Deltacloud API Hardware Profiles' do
+  include Deltacloud::Test
+
+  it 'must advertise have the hardware_profiles collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=hardware_profiles]').wont_be_empty
+  end
+
+  it 'should respond with HTTP_OK when accessing the :hardware_profiles collection with authentication' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:hardware_profiles)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "hardware_profiles" element on top level' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    xml_response.root.name.must_equal 'hardware_profiles'
+  end
+
+  it 'must have some "hardware_profile" elements inside "hardware_profiles"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each hardware_profile in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "hardware_profile" element in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the hardware_profile' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:hardware_profiles) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each hardware_profile in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'should have the "property" element defined if not the opaque hardware_profile' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').wont_be_empty
+    end
+  end
+
+  it 'must define the :kind attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:kind].wont_be_nil }
+    end
+  end
+
+  it 'must define the :name attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:name].wont_be_nil }
+    end
+  end
+
+  it 'must define the :unit attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:unit].wont_be_nil }
+    end
+  end
+
+  it 'must define the :value attribute for each "property" ' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each { |p| p[:value].wont_be_nil }
+    end
+  end
+
+  it 'must define the "param" element if property kind is not "fixed"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] == 'fixed'
+        (p/'param').wont_be_empty
+        (p/'param').size.must_equal 1
+        (p/'param').first[:href].wont_be_nil
+        (p/'param').first[:href].must_match /^http/
+        (p/'param').first[:method].wont_be_nil
+        (p/'param').first[:name].wont_be_nil
+        (p/'param').first[:operation].wont_be_nil
+      end
+    end
+  end
+
+  it 'must provide the list of valid values when the property is defined as "enum"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'enum'
+        (p/'enum/entry').wont_be_empty
+        (p/'enum/entry').each { |e| e[:value].wont_be_nil }
+      end
+    end
+  end
+
+  it 'must provide the range of valid values when the property is defined as "range"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'range'
+        (p/'range').wont_be_empty
+        (p/'range').size.must_equal 1
+        (p/'range').first[:first].wont_be_nil
+        (p/'range').first[:last].wont_be_nil
+      end
+    end
+  end
+
+  it 'must provide the default value within the range if property defined as "range"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'range'
+        ((p/'range').first[:first].to_i..(p/'range').first[:last].to_i).include?(p[:value].to_i).must_equal true
+      end
+    end
+  end
+
+  it 'must provide the default value that is included in enum list if property defined as "enum"' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      next if r[:id] == 'opaque'
+      (r/'property').each do |p|
+        next if p[:kind] != 'enum'
+        (p/'enum/entry').map { |e| e[:value] }.include?(p[:value]).must_equal true
+      end
+    end
+  end
+
+  it 'must return the full "hardware_profile" when following the URL in hardware_profile element' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      get collection_url(:hardware_profiles) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the hardware_profile and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:hardware_profiles)
+    (xml_response/'hardware_profiles/hardware_profile').each do |r|
+      get collection_url(:hardware_profiles) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+end
diff --git a/server/tests/drivers/api/images_test.rb b/server/tests/drivers/api/images_test.rb
new file mode 100644
index 0000000..3faf752
--- /dev/null
+++ b/server/tests/drivers/api/images_test.rb
@@ -0,0 +1,194 @@
+describe 'Deltacloud API Images' do
+  include Deltacloud::Test
+
+  it 'must advertise have the images collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=images]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "image" collection' do
+    get collection_url(:images)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :images collection with authentication' do
+    auth_as_mock
+    get collection_url(:images)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:images)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:images)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "images" element on top level' do
+    auth_as_mock
+    get collection_url(:images)
+    xml_response.root.name.must_equal 'images'
+  end
+
+  it 'must have some "image" elements inside "images"' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each image in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "image" element in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:images) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each image in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must have the "state" element defined for each image in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      (r/'state').wont_be_empty
+    end
+  end
+
+  it 'must return the full "image" when following the URL in image element' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the image and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "name" element for the image and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
+  end
+
+  it 'should have the "owner_id" element for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'owner_id').wont_be_empty
+    end
+  end
+
+  it 'should have the "description" element for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'description').wont_be_empty
+    end
+  end
+
+  it 'should have the "architecture" element for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'architecture').wont_be_empty
+    end
+  end
+
+  it 'should include the list of compatible hardware_profiles for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'hardware_profiles/hardware_profile').wont_be_empty
+      (xml_response/'hardware_profiles/hardware_profile').each do |hwp|
+        hwp[:href].wont_be_nil
+        hwp[:href].must_match /^http/
+        hwp[:id].wont_be_nil
+        hwp[:href].must_match /\/#{hwp[:id]}$/
+        hwp[:rel].must_equal 'hardware_profile'
+      end
+    end
+  end
+
+  it 'should advertise the list of actions that can be executed for each image' do
+    auth_as_mock
+    get collection_url(:images)
+    (xml_response/'images/image').each do |r|
+      get collection_url(:images) + '/' + r[:id]
+      (xml_response/'actions/link').wont_be_empty
+      (xml_response/'actions/link').each do |l|
+        l[:href].wont_be_nil
+        l[:href].must_match /^http/
+        l[:method].wont_be_nil
+        l[:rel].wont_be_nil
+      end
+    end
+  end
+
+  it 'should give client HTML form to create new image' do
+    auth_as_mock
+    header 'Accept', 'text/html'
+    get collection_url(:images) + '/new'
+    last_response.status.must_equal 200
+  end
+
+end
diff --git a/server/tests/drivers/api/instances_test.rb b/server/tests/drivers/api/instances_test.rb
new file mode 100644
index 0000000..c601a6f
--- /dev/null
+++ b/server/tests/drivers/api/instances_test.rb
@@ -0,0 +1,340 @@
+describe 'Deltacloud API instances' do
+  include Deltacloud::Test
+
+  it 'must advertise have the instances collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=instances]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "instance" collection' do
+    get collection_url(:instances)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :instances collection with authentication' do
+    auth_as_mock
+    get collection_url(:instances)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:instances)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:instances)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "instances" element on top level' do
+    auth_as_mock
+    get collection_url(:instances)
+    xml_response.root.name.must_equal 'instances'
+  end
+
+  it 'must have some "instance" elements inside "instances"' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each instance in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "instance" element in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:instances) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each instance in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must have the "state" element defined for each instance in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      (r/'state').wont_be_empty
+      (r/'state').first.must_match /(RUNNING|STOPPED|PENDING)/
+    end
+  end
+
+  it 'must return the full "instance" when following the URL in instance element' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the instance and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "name" element for the instance and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
+  end
+
+  it 'must have the "owner_id" element for the instance and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'owner_id').wont_be_empty
+      (xml_response/'owner_id').first.text.must_equal((r/'owner_id').first.text)
+    end
+  end
+
+  it 'must link to the realm that was used to during instance creation' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'realm').wont_be_empty
+      (xml_response/'realm').size.must_equal 1
+      (xml_response/'realm').first[:id].wont_be_nil
+      (xml_response/'realm').first[:href].wont_be_nil
+      (xml_response/'realm').first[:href].must_match /\/#{(xml_response/'realm').first[:id]}$/
+    end
+  end
+
+  it 'must link to the image that was used to during instance creation' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'image').wont_be_empty
+      (xml_response/'image').size.must_equal 1
+      (xml_response/'image').first[:id].wont_be_nil
+      (xml_response/'image').first[:href].wont_be_nil
+      (xml_response/'image').first[:href].must_match /\/#{(xml_response/'image').first[:id]}$/
+    end
+  end
+
+  it 'must link to the hardware_profile that was used to during instance creation' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'hardware_profile').wont_be_empty
+      (xml_response/'hardware_profile').size.must_equal 1
+      (xml_response/'hardware_profile').first[:id].wont_be_nil
+      (xml_response/'hardware_profile').first[:href].wont_be_nil
+      (xml_response/'hardware_profile').first[:href].must_match /\/#{(xml_response/'hardware_profile').first[:id]}$/
+    end
+  end
+
+  it 'should advertise the public and private addresses of the instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'public_addresses').wont_be_empty
+      (xml_response/'public_addresses').size.must_equal 1
+      (xml_response/'public_addresses/address').each do |a|
+        a[:type].wont_be_nil
+        a.text.strip.wont_be_empty
+      end
+      (xml_response/'private_addresses').wont_be_empty
+      (xml_response/'private_addresses').size.must_equal 1
+      (xml_response/'private_addresses/address').each do |a|
+        a[:type].wont_be_nil
+        a.text.strip.wont_be_empty
+      end
+    end
+  end
+
+  it 'should advertise the storage volumes used by the instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'storage_volumes').wont_be_empty
+    end
+  end
+
+  it 'should advertise the list of actions that can be executed for each instance' do
+    auth_as_mock
+    get collection_url(:instances)
+    (xml_response/'instances/instance').each do |r|
+      get collection_url(:instances) + '/' + r[:id]
+      (xml_response/'actions/link').wont_be_empty
+      (xml_response/'actions/link').each do |l|
+        l[:href].wont_be_nil
+        l[:href].must_match /^http/
+        l[:method].wont_be_nil
+        l[:rel].wont_be_nil
+      end
+    end
+  end
+
+  it 'should allow to create and destroy new instance using the first available image without realm' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    image_id.wont_be_nil
+    post collection_url(:instances), {
+      :image_id => image_id
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+  it 'should allow to create and destroy new instance using the first available image within first realm' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    get collection_url(:realms)
+    realm_id = (xml_response/'realms/realm').first[:id]
+    image_id.wont_be_nil
+    realm_id.wont_be_nil
+    post collection_url(:instances), {
+      :image_id => image_id,
+      :realm_id => realm_id,
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    (xml_response/'instance/realm').first[:id].must_equal realm_id
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+  it 'should allow to create and destroy new instance using the first available image with user defined name' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    image_id.wont_be_nil
+    name = "i#{Time.now.to_i}"
+    post collection_url(:instances), {
+      :image_id => image_id,
+      :name => name
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    (xml_response/'instance/name').first.text.must_equal name
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+  it 'should allow to create and destroy new instance using the first available image and first hardware_profile' do
+    auth_as_mock
+    get collection_url(:images)
+    image_id = (xml_response/'images/image').first[:id]
+    get collection_url(:hardware_profiles)
+    hwp_id = (xml_response/'hardware_profiles/hardware_profile').first[:id]
+    image_id.wont_be_nil
+    name = "i#{Time.now.to_i}"
+    post collection_url(:instances), {
+      :image_id => image_id,
+      :hwp_id => hwp_id
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    last_response.headers['Location'].wont_be_nil # Location header must be set, pointing to new the instance
+    instance_id = last_response.headers['Location'].split('/').last
+    # Get the instance and check if ID and image is set correctly
+    get collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 200 # HTTP_OK
+    (xml_response/'instance').first[:id].must_equal instance_id
+    (xml_response/'instance/image').first[:id].must_equal image_id
+    (xml_response/'instance/hardware_profile').first[:id].must_equal hwp_id
+    # If instance is RUNNING then stop it
+    if (xml_response/'instance/state').first.text == 'RUNNING'
+      post collection_url(:instances) + '/' + instance_id + '/stop'
+      last_response.status.must_equal 202 # HTTP_NO_CONTENT
+    end
+    # Delete created instance
+    delete collection_url(:instances) + '/' + instance_id
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+end
diff --git a/server/tests/drivers/api/keys_test.rb b/server/tests/drivers/api/keys_test.rb
new file mode 100644
index 0000000..9267b5a
--- /dev/null
+++ b/server/tests/drivers/api/keys_test.rb
@@ -0,0 +1,158 @@
+describe 'Deltacloud API Keys' do
+  include Deltacloud::Test
+
+  it 'must advertise have the keys collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=keys]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "key" collection' do
+    get collection_url(:keys)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :keys collection with authentication' do
+    auth_as_mock
+    get collection_url(:keys)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:keys)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:keys)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "keys" element on top level' do
+    auth_as_mock
+    get collection_url(:keys)
+    xml_response.root.name.must_equal 'keys'
+  end
+
+  it 'must have some "key" elements inside "keys"' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').wont_be_empty
+  end
+
+  it 'must tell the kind of "key" elements inside "keys"' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |k|
+      k[:type].must_match /(key|password)/
+    end
+  end
+
+  it 'must provide the :id attribute for each key in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "key" element in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the key' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:keys) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each key in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+
+  it 'must return the full "key" when following the URL in key element' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the key and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "name" element for the key and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
+  end
+
+  it 'should advertise the list of actions that can be executed for each key' do
+    auth_as_mock
+    get collection_url(:keys)
+    (xml_response/'keys/key').each do |r|
+      get collection_url(:keys) + '/' + r[:id]
+      (xml_response/'actions/link').wont_be_empty
+      (xml_response/'actions/link').each do |l|
+        l[:href].wont_be_nil
+        l[:href].must_match /^http/
+        l[:method].wont_be_nil
+        l[:rel].wont_be_nil
+      end
+    end
+  end
+
+  it 'should allow to create a new key and then remove it' do
+    auth_as_mock
+    key_name = Time.now.to_i.to_s
+    post collection_url(:keys), {
+      :name => 'test_key_'+key_name
+    }
+    last_response.status.must_equal 201 # HTTP_CREATED
+    get collection_url(:keys) + '/' + 'test_key_'+key_name
+    last_response.status.must_equal 200 # HTTP_OK
+    delete collection_url(:keys) + '/' + 'test_key_'+key_name
+    last_response.status.must_equal 204 # HTTP_NO_CONTENT
+  end
+
+end
diff --git a/server/tests/drivers/api/realms_test.rb b/server/tests/drivers/api/realms_test.rb
new file mode 100644
index 0000000..6bc9101
--- /dev/null
+++ b/server/tests/drivers/api/realms_test.rb
@@ -0,0 +1,129 @@
+describe 'Deltacloud API Realms' do
+  include Deltacloud::Test
+
+  it 'must advertise have the realms collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=realms]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "realm" collection' do
+    get collection_url(:realms)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :realms collection with authentication' do
+    auth_as_mock
+    get collection_url(:realms)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:realms)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:realms)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "realms" element on top level' do
+    auth_as_mock
+    get collection_url(:realms)
+    xml_response.root.name.must_equal 'realms'
+  end
+
+  it 'must have some "realm" elements inside "realms"' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each realm in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "realm" element in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the realm' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:realms) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each realm in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must have the "state" element defined for each realm in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      (r/'state').wont_be_empty
+    end
+  end
+
+  it 'must return the full "realm" when following the URL in realm element' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      get collection_url(:realms) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the realm and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      get collection_url(:realms) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+  it 'must have the "state" element for the realm and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:realms)
+    (xml_response/'realms/realm').each do |r|
+      get collection_url(:realms) + '/' + r[:id]
+      (xml_response/'state').wont_be_empty
+      (xml_response/'state').first.text.must_equal((r/'state').first.text)
+    end
+  end
+
+end
diff --git a/server/tests/drivers/api/storage_snapshots_test.rb b/server/tests/drivers/api/storage_snapshots_test.rb
new file mode 100644
index 0000000..52ea847
--- /dev/null
+++ b/server/tests/drivers/api/storage_snapshots_test.rb
@@ -0,0 +1,111 @@
+describe 'Deltacloud API storage_snapshots' do
+  include Deltacloud::Test
+
+  it 'must advertise have the storage_snapshots collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=storage_snapshots]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "storage_snapshot" collection' do
+    get collection_url(:storage_snapshots)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :storage_snapshots collection with authentication' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:storage_snapshots)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "storage_snapshots" element on top level' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    xml_response.root.name.must_equal 'storage_snapshots'
+  end
+
+  it 'must have some "storage_snapshot" elements inside "storage_snapshots"' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each storage_snapshot in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "storage_snapshot" element in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the storage_snapshot' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:storage_snapshots) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each storage_snapshot in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must return the full "storage_snapshot" when following the URL in storage_snapshot element' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      get collection_url(:storage_snapshots) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the storage_snapshot and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:storage_snapshots)
+    (xml_response/'storage_snapshots/storage_snapshot').each do |r|
+      get collection_url(:storage_snapshots) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+end
diff --git a/server/tests/drivers/api/storage_volumes_test.rb b/server/tests/drivers/api/storage_volumes_test.rb
new file mode 100644
index 0000000..cbafd5d
--- /dev/null
+++ b/server/tests/drivers/api/storage_volumes_test.rb
@@ -0,0 +1,119 @@
+describe 'Deltacloud API storage_volumes' do
+  include Deltacloud::Test
+
+  it 'must advertise have the storage_volumes collection in API entrypoint' do
+    get API_ROOT_URL
+    (xml_response/'api/link[@rel=storage_volumes]').wont_be_empty
+  end
+
+  it 'must require authentication to access the "storage_volume" collection' do
+    get collection_url(:storage_volumes)
+    last_response.status.must_equal 401
+  end
+
+  it 'should respond with HTTP_OK when accessing the :storage_volumes collection with authentication' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    last_response.status.must_equal 200
+  end
+
+  it 'should support the JSON media type' do
+    auth_as_mock
+    header 'Accept', 'application/json'
+    get collection_url(:storage_volumes)
+    last_response.status.must_equal 200
+    last_response.headers['Content-Type'].must_equal 'application/json'
+  end
+
+  it 'must include the ETag in HTTP headers' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    last_response.headers['ETag'].wont_be_nil
+  end
+
+  it 'must have the "storage_volumes" element on top level' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    xml_response.root.name.must_equal 'storage_volumes'
+  end
+
+  it 'must have some "storage_volume" elements inside "storage_volumes"' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').wont_be_empty
+  end
+
+  it 'must provide the :id attribute for each storage_volume in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:id].wont_be_nil
+    end
+  end
+
+  it 'must include the :href attribute for each "storage_volume" element in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:href].wont_be_nil
+    end
+  end
+
+  it 'must use the absolute URL in each :href attribute' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:href].must_match /^http/
+    end
+  end
+
+  it 'must have the URL ending with the :id of the storage_volume' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      r[:href].must_match /#{r[:id]}$/
+    end
+  end
+
+  it 'must return the list of valid parameters for the :index action' do
+    auth_as_mock
+    options collection_url(:storage_volumes) + '/index'
+    last_response.headers['Allow'].wont_be_nil
+  end
+
+  it 'must have the "name" element defined for each storage_volume in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      (r/'name').wont_be_empty
+    end
+  end
+
+  it 'must have the "state" element defined for each storage_volume in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      (r/'state').wont_be_empty
+    end
+  end
+
+  it 'must return the full "storage_volume" when following the URL in storage_volume element' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      get collection_url(:storage_volumes) + '/' + r[:id]
+      last_response.status.must_equal 200
+    end
+  end
+
+  it 'must have the "name" element for the storage_volume and it should match with the one in collection' do
+    auth_as_mock
+    get collection_url(:storage_volumes)
+    (xml_response/'storage_volumes/storage_volume').each do |r|
+      get collection_url(:storage_volumes) + '/' + r[:id]
+      (xml_response/'name').wont_be_empty
+      (xml_response/'name').first.text.must_equal((r/'name').first.text)
+    end
+  end
+
+end
-- 
1.7.10


[PATCH core 02/32] Core: Added collections directory with Rabbit collections

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 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 +++++++++
 13 files changed, 1045 insertions(+)
 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

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


[PATCH core 04/32] Core: Removed obsoleted registration of the rack-accept middleware

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/sinatra/rack_accept.rb        |    4 ----
 server/lib/sinatra/rack_matrix_params.rb |    4 +---
 2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/server/lib/sinatra/rack_accept.rb b/server/lib/sinatra/rack_accept.rb
index 2ad52c7..e4a0f1f 100644
--- a/server/lib/sinatra/rack_accept.rb
+++ b/server/lib/sinatra/rack_accept.rb
@@ -12,11 +12,8 @@
 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
 
-require 'sinatra/base'
 require 'rack/accept'
 
-use Rack::Accept
-
 module Rack
 
   module RespondTo
@@ -26,7 +23,6 @@ module Rack
     # We need to overide the default render method to supply correct path to the
     # template, since Sinatra is by default looking in the current __FILE__ path
     def self.registered(app)
-      app.helpers Rack::RespondTo::Helpers
       app.class_eval do
         alias :render_without_format :render
         def render(*args, &block)
diff --git a/server/lib/sinatra/rack_matrix_params.rb b/server/lib/sinatra/rack_matrix_params.rb
index 177e745..0d9339b 100644
--- a/server/lib/sinatra/rack_matrix_params.rb
+++ b/server/lib/sinatra/rack_matrix_params.rb
@@ -51,9 +51,7 @@ module Rack
         while param=sub_components.pop do
           if value
             matrix_params[sub_components.first] ||= {}
-            matrix_params[sub_components.first].merge!(
-                                                       param => value
-                                                       )
+            matrix_params[sub_components.first].merge!(param => value)
             value=nil
             next
           else
-- 
1.7.10


Re: [PATCH core 06/32] Core: Added support for autoloading all Deltacloud models

Posted by David Lutterkort <lu...@redhat.com>.
On Thu, 2012-05-10 at 10:06 +0200, Michal Fojtik wrote:
> On 05/10/12, David Lutterkort wrote:
> > On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> > > From: Michal Fojtik <mf...@redhat.com>
> > 
> > This also is a lot of magic to me - is there really that much to gain
> > from not having to add a new model to the list of requires here ?
> 
> Yeah, well I usually end up with code like this when I need to type
> the same thing too many times. But not a problem, I'll add the require
> there to make it more clean.

Think of the poor guy who looks at this for the first time ;)

David



Re: [PATCH core 06/32] Core: Added support for autoloading all Deltacloud models

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/10/12, David Lutterkort wrote:
> On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> > From: Michal Fojtik <mf...@redhat.com>
> 
> This also is a lot of magic to me - is there really that much to gain
> from not having to add a new model to the list of requires here ?

Yeah, well I usually end up with code like this when I need to type
the same thing too many times. But not a problem, I'll add the require
there to make it more clean.

  -- michal

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

Re: [PATCH core 06/32] Core: Added support for autoloading all Deltacloud models

Posted by David Lutterkort <lu...@redhat.com>.
On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>

This also is a lot of magic to me - is there really that much to gain
from not having to add a new model to the list of requires here ?

David



[PATCH core 06/32] Core: Added support for autoloading all Deltacloud models

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


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

diff --git a/server/lib/deltacloud/models.rb b/server/lib/deltacloud/models.rb
index a794192..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,19 +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_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
-- 
1.7.10


Re: [PATCH core 14/32] Core: Updated drivers to remove base_driver require and added autoloading of driver

Posted by Michal Fojtik <mf...@redhat.com>.
On 04/18/12, Koper, Dies wrote:
> Hi Michal,
> 
> > -          running.to( :stopping )       .on( :destroy )
> > +          running.to( :shutting_down )  .on( :destroy )
> 
> In commit 09bfd939db278978d87539534ceda3465737acc3 David changed this
> state to be consistently :stopping.
> Does this mean we're reverting that and change the state consistently to
> :shutting_down?

Good catch Dies, thanks for this. When I forked DC I must miss this update.
I'll remove this state as David did before pushing. (/note added ;-)

  -- Michal


> 
> Cheers,
> Dies Koper
> 
> 
> 
> > -----Original Message-----
> > From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> > Sent: Tuesday, 17 April 2012 11:40 PM
> > To: dev@deltacloud.apache.org
> > Subject: [PATCH core 14/32] Core: Updated drivers to remove
> base_driver
> > require and added autoloading of driver
> > 
> > From: Michal Fojtik <mf...@redhat.com>
> > 
> > 
> > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > ---
> >  server/lib/deltacloud/drivers.rb                   |   48 +------
> >  .../lib/deltacloud/drivers/azure/azure_driver.rb   |    4 -
> >  .../lib/deltacloud/drivers/condor/condor_driver.rb |    9 +-
> >  server/lib/deltacloud/drivers/ec2/ec2_driver.rb    |   18 +--
> >  .../drivers/eucalyptus/eucalyptus_driver.rb        |    4 -
> >  server/lib/deltacloud/drivers/features.rb          |  111
> ++++++++++++++++
> >  .../lib/deltacloud/drivers/gogrid/gogrid_driver.rb |    6 -
> >  .../lib/deltacloud/drivers/google/google_driver.rb |    3 -
> >  server/lib/deltacloud/drivers/mock/mock_client.rb  |   11 --
> >  server/lib/deltacloud/drivers/mock/mock_driver.rb  |   21 +--
> >  .../drivers/mock/mock_driver_cimi_methods.rb       |  139
> --------------------
> >  .../drivers/opennebula/opennebula_driver.rb        |    8 +-
> >  .../drivers/openstack/openstack_driver.rb          |   12 +-
> >  .../drivers/rackspace/rackspace_driver.rb          |    9 +-
> >  .../lib/deltacloud/drivers/rhevm/rhevm_driver.rb   |   17 +--
> >  .../drivers/rimuhosting/rimuhosting_client.rb      |   17 ++-
> >  .../drivers/rimuhosting/rimuhosting_driver.rb      |   11 +-
> >  .../drivers/terremark/terremark_driver.rb          |    7 +-
> >  .../deltacloud/drivers/vsphere/vsphere_driver.rb   |   15 +--
> >  19 files changed, 160 insertions(+), 310 deletions(-)
> >  create mode 100644 server/lib/deltacloud/drivers/features.rb
> > 
> > diff --git a/server/lib/deltacloud/drivers.rb
> > b/server/lib/deltacloud/drivers.rb
> > index dfc998d..14e7ee0 100644
> > --- a/server/lib/deltacloud/drivers.rb
> > +++ b/server/lib/deltacloud/drivers.rb
> > @@ -13,25 +13,15 @@
> >  # License for the specific language governing permissions and
> limitations
> >  # under the License.
> > 
> > -module Deltacloud
> > +require_relative 'drivers/exceptions'
> > +require_relative 'drivers/base_driver'
> > +require_relative 'drivers/features'
> > +require 'yaml'
> > 
> > +module Deltacloud
> >    module Drivers
> > 
> > -    require 'yaml'
> > -
> > -    DEFAULT_COLLECTIONS = [
> > -      :hardware_profiles,
> > -      :images,
> > -      :instances,
> > -      :instance_states,
> > -      :realms,
> > -      :storage_volumes,
> > -      :storage_snapshots
> > -    ]
> > -
> > -    DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
> > -
> > -    def driver_config
> > +    def self.driver_config
> >        if Thread::current[:drivers].nil?
> >          Thread::current[:drivers] = {}
> >          top_srcdir = File.join(File.dirname(__FILE__), '..', '..')
> > @@ -42,31 +32,5 @@ module Deltacloud
> >        Thread::current[:drivers]
> >      end
> > 
> > -    def driver_symbol
> > -      (Thread.current[:driver] || DRIVER).to_sym
> > -    end
> > -
> > -    def driver_name
> > -      driver_config[:"#{driver_symbol}"][:name]
> > -    end
> > -
> > -    def driver_class
> > -      basename = driver_config[:"#{driver_symbol}"][:class] ||
> > "#{driver_name}Driver"
> > -      Deltacloud::Drivers.const_get(driver_name).const_get(basename)
> > -    end
> > -
> > -    def driver_source_name
> > -      File.join("deltacloud", "drivers", "#{driver_symbol}",
> > "#{driver_symbol}_driver.rb")
> > -    end
> > -
> > -    def driver_mock_source_name
> > -      return File.join('deltacloud', 'drivers', "#{driver_symbol}",
> > -		       "#{driver_symbol}_driver.rb") if driver_name.eql?
> > 'Mock'
> > -    end
> > -
> > -    def driver
> > -      require driver_source_name
> > -      @driver ||= driver_class.new
> > -    end
> >    end
> >  end
> > diff --git a/server/lib/deltacloud/drivers/azure/azure_driver.rb
> > b/server/lib/deltacloud/drivers/azure/azure_driver.rb
> > index 24feeb7..db2b6c6 100644
> > --- a/server/lib/deltacloud/drivers/azure/azure_driver.rb
> > +++ b/server/lib/deltacloud/drivers/azure/azure_driver.rb
> > @@ -15,7 +15,6 @@
> >  # under the License.
> > 
> >  #Windows Azure (WAZ) gem at http://github.com/johnnyhalife/waz-
> > storage
> > -require 'deltacloud/base_driver'
> >  require 'waz-blobs'
> > 
> >  module Deltacloud
> > @@ -24,9 +23,6 @@ module Deltacloud
> > 
> >  class AzureDriver < Deltacloud::BaseDriver
> > 
> > -  def supported_collections; [:buckets]
> > -  end
> > -
> >  #--
> >  # Buckets
> >  #--
> > diff --git a/server/lib/deltacloud/drivers/condor/condor_driver.rb
> > b/server/lib/deltacloud/drivers/condor/condor_driver.rb
> > index f5cb741..c139b62 100644
> > --- a/server/lib/deltacloud/drivers/condor/condor_driver.rb
> > +++ b/server/lib/deltacloud/drivers/condor/condor_driver.rb
> > @@ -14,9 +14,6 @@
> >  # under the License.
> >  #
> > 
> > -require 'deltacloud/base_driver'
> > -
> > -
> >  class Instance
> >    def self.convert_condor_state(state_id)
> >      case state_id
> > @@ -44,10 +41,6 @@ module Deltacloud
> >          feature :instances, :user_data
> >          feature :instances, :authentication_password
> > 
> > -        def supported_collections
> > -          DEFAULT_COLLECTIONS - [ :storage_volumes,
> :storage_snapshots ]
> > -        end
> > -
> >          CONDOR_MAPPER_DIR = ENV['CONDOR_MAPPER_DIR'] || '/var/tmp'
> > 
> >          def hardware_profiles(credentials, opts={})
> > @@ -175,7 +168,7 @@ module Deltacloud
> >            pending.to( :running )        .automatically
> >            pending.to( :finish )         .on(:destroy)
> >            running.to( :running )        .on( :reboot )
> > -          running.to( :stopping )       .on( :destroy )
> > +          running.to( :shutting_down )  .on( :destroy )
> >            pending.to( :finish )         .automatically
> >          end
> > 
> > diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> > b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> > index 60e86e8..01b76b4 100644
> > --- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> > +++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> > @@ -14,7 +14,6 @@
> >  # under the License.
> >  #
> > 
> > -require 'deltacloud/base_driver'
> >  require 'aws'
> > 
> >  class Instance
> > @@ -29,13 +28,8 @@ end
> > 
> >  module Deltacloud
> >    module Drivers
> > -    module EC2
> > -      class EC2Driver < Deltacloud::BaseDriver
> > -
> > -        def supported_collections
> > -
> > -          DEFAULT_COLLECTIONS +
> > [ :keys, :buckets, :load_balancers, :addresses, :firewalls ]
> > -        end
> > +    module Ec2
> > +      class Ec2Driver < Deltacloud::BaseDriver
> > 
> >          feature :instances, :user_data
> >          feature :instances, :authentication_key
> > @@ -127,8 +121,7 @@ module Deltacloud
> >            stopped.to( :running )        .on( :start )
> >            running.to( :running )        .on( :reboot )
> >            running.to( :stopping )       .on( :stop )
> > -          stopping.to(:stopped)         .automatically
> > -          stopping.to(:finish)          .automatically
> > +          shutting_down.to( :stopped )  .automatically
> >            stopped.to( :finish )         .automatically
> >          end
> > 
> > @@ -413,9 +406,7 @@ module Deltacloud
> >            safely do
> >              s3_bucket = s3_client.bucket(opts['bucket'])
> >              if(opts[:id])
> > -              s3_key = s3_bucket.key(opts[:id], true)
> > -              raise "Blob #{opts[:id]} in Bucket #{opts['bucket']}
> NotFound"
> > unless s3_key.exists?
> > -              blobs << convert_object(s3_key)
> > +              blobs << convert_object(s3_bucket.key(opts[:id], true))
> >              else
> >                s3_bucket.keys({}, true).each do |s3_object|
> >                  blobs << convert_object(s3_object)
> > @@ -471,7 +462,6 @@ module Deltacloud
> >            blob_meta = {}
> >            safely do
> >              the_blob =
> s3_client.bucket(opts['bucket']).key(opts[:id], true)
> > -            raise "Blob #{opts[:id]} in Bucket #{opts['bucket']}
> NotFound" unless
> > the_blob.exists?
> >              blob_meta = the_blob.meta_headers
> >            end
> >          end
> > diff --git
> a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> > b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> > index 2270178..54c1eed 100644
> > --- a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> > +++ b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> > @@ -21,10 +21,6 @@ module Deltacloud
> >      module Eucalyptus
> >        class EucalyptusDriver < EC2::EC2Driver
> > 
> > -        def supported_collections
> > -          DEFAULT_COLLECTIONS + [ :keys, :buckets, :addresses,
> :firewalls ]
> > -        end
> > -
> >          feature :instances, :user_data
> >          feature :instances, :authentication_key
> >          feature :instances, :firewalls
> > diff --git a/server/lib/deltacloud/drivers/features.rb
> > b/server/lib/deltacloud/drivers/features.rb
> > new file mode 100644
> > index 0000000..01d8656
> > --- /dev/null
> > +++ b/server/lib/deltacloud/drivers/features.rb
> > @@ -0,0 +1,111 @@
> > +# Licensed to the Apache Software Foundation (ASF) under one or more
> > +# contributor license agreements.  See the NOTICE file distributed
> with
> > +# this work for additional information regarding copyright ownership.
> The
> > +# ASF licenses this file to you under the Apache License, Version 2.0
> (the
> > +# "License"); you may not use this file except in compliance with the
> > +# License.  You may obtain a copy of the License at
> > +#
> > +#       http://www.apache.org/licenses/LICENSE-2.0
> > +#
> > +# Unless required by applicable law or agreed to in writing, software
> > +# distributed under the License is distributed on an "AS IS" BASIS,
> > WITHOUT
> > +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > See the
> > +# License for the specific language governing permissions and
> limitations
> > +# under the License.
> > +
> > +module Deltacloud
> > +  module InstanceFeatures
> > +
> > +    def self.included(k)
> > +      current_features = features
> > +      k.instance_eval do
> > +        features(&current_features)
> > +      end
> > +    end
> > +
> > +    def self.features(&block)
> > +      block_given? ? @features = block : @features || Proc.new{}
> > +    end
> > +
> > +    features do
> > +
> > +      feature :user_name, :for => :instances do
> > +        description "Allow to set user-defined name for the instance"
> > +        operation :create do
> > +          param :name, :string, :optional
> > +        end
> > +      end
> > +
> > +      feature :user_data, :for => :instances do
> > +        description "Allow to pass user-defined data into the
> instance"
> > +        operation :create do
> > +          param :user_data, :string, :optional
> > +        end
> > +      end
> > +
> > +      feature :user_iso, :for => :instances do
> > +        description  "Base64 encoded gzipped ISO file will be
> accessible as CD-
> > ROM drive in instance"
> > +        operation :create do
> > +          param :user_iso, :string, :optional
> > +        end
> > +      end
> > +
> > +      feature :firewalls, :for => :instances do
> > +        description "Put instance in one or more firewalls (security
> groups) on
> > launch"
> > +        operation :create do
> > +          param :firewalls, :array, :optional, nil, "Array of
> firewall ID strings"
> > +          "Array of firewall (security group) id"
> > +        end
> > +      end
> > +
> > +      feature :authentication_key, :for => :instances do
> > +        operation :create do
> > +          param :keyname, :string,  :optional, [], "Key
> authentification
> > method"
> > +        end
> > +        operation :show do
> > +        end
> > +      end
> > +
> > +      feature :authentication_password, :for => :instances do
> > +        operation :create do
> > +          param :password, :string, :optional
> > +        end
> > +      end
> > +
> > +      feature :hardware_profiles, :for => :instances do
> > +        description "Size instances according to changes to a
> hardware
> > profile"
> > +        # The parameters are filled in from the hardware profiles
> > +      end
> > +
> > +      feature :register_to_load_balancer, :for => :instances do
> > +        description "Register instance to load balancer"
> > +        operation :create do
> > +          param :load_balancer_id, :string, :optional
> > +        end
> > +      end
> > +
> > +      feature :instance_count, :for => :instances do
> > +        description "Number of instances to be launch with at once"
> > +        operation :create do
> > +          param :instance_count,  :string,  :optional
> > +        end
> > +      end
> > +
> > +      feature :attach_snapshot, :for => :instances do
> > +        description "Attach an snapshot to instance on create"
> > +        operation :create do
> > +          param :snapshot_id,  :string,  :optional
> > +          param :device_name,  :string,  :optional
> > +        end
> > +      end
> > +
> > +      feature :sandboxing, :for => :instances do
> > +        description "Allow lanuching sandbox images"
> > +        operation :create do
> > +          param :sandbox, :string,  :optional
> > +        end
> > +      end
> > +    end
> > +
> > +  end
> > +end
> > diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> > b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> > index 285f58f..2a83c24 100644
> > --- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> > +++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> > @@ -14,7 +14,6 @@
> >  # License for the specific language governing permissions and
> limitations
> >  # under the License.
> > 
> > -require 'deltacloud/base_driver'
> >  require 'deltacloud/drivers/gogrid/gogrid_client'
> > 
> >  class Instance
> > @@ -61,11 +60,6 @@ class GogridDriver < Deltacloud::BaseDriver
> >      @hardware_profiles
> >    end
> > 
> > -  def supported_collections
> > -    DEFAULT_COLLECTIONS.reject! { |c|
> > [ :storage_volumes, :storage_snapshots ].include?(c) }
> > -    DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
> > -  end
> > -
> >    def images(credentials, opts=nil)
> >      imgs = []
> >      if opts and opts[:id]
> > diff --git a/server/lib/deltacloud/drivers/google/google_driver.rb
> > b/server/lib/deltacloud/drivers/google/google_driver.rb
> > index 2ffb5f8..8bc6f25 100644
> > --- a/server/lib/deltacloud/drivers/google/google_driver.rb
> > +++ b/server/lib/deltacloud/drivers/google/google_driver.rb
> > @@ -21,9 +21,6 @@ module Deltacloud
> > 
> >  class GoogleDriver < Deltacloud::BaseDriver
> > 
> > -  def supported_collections; [:buckets]
> > -  end
> > -
> >    feature :buckets, :bucket_location
> > 
> >  #--
> > diff --git a/server/lib/deltacloud/drivers/mock/mock_client.rb
> > b/server/lib/deltacloud/drivers/mock/mock_client.rb
> > index 94c56af..248cc49 100644
> > --- a/server/lib/deltacloud/drivers/mock/mock_client.rb
> > +++ b/server/lib/deltacloud/drivers/mock/mock_client.rb
> > @@ -91,17 +91,6 @@ module Deltacloud::Drivers::Mock
> >        FileUtils.rm(fname) if File::exists?(fname)
> >      end
> > 
> > -    def store_cimi(collection, obj)
> > -      raise "Why no obj.name?" unless obj.name
> > -      File::open(cimi_file(collection, obj.name), "w") { |f|
> > f.write(obj.to_json) }
> > -    end
> > -
> > -    def destroy_cimi(collection, id)
> > -      fname = cimi_file(collection, id)
> > -      raise "No such object: #{id} in #{collection} collection"
> unless
> > File::exists?(fname)
> > -      FileUtils.rm(fname)
> > -    end
> > -
> >      def load_all_cimi(model_name)
> >          model_files = Dir[File::join(cimi_dir(model_name), "*.json")]
> >          model_files.map{|f| File.read(f)}
> > diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb
> > b/server/lib/deltacloud/drivers/mock/mock_driver.rb
> > index b58872c..15f06fb 100644
> > --- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
> > +++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
> > @@ -14,28 +14,16 @@
> >  # License for the specific language governing permissions and
> limitations
> >  # under the License.
> > 
> > -
> >  require 'yaml'
> >  require 'base64'
> >  require 'etc'
> > -require 'deltacloud/base_driver'
> > -require 'deltacloud/drivers/mock/mock_client'
> > -require 'deltacloud/drivers/mock/mock_driver_cimi_methods'
> > +require_relative 'mock_client'
> > +require_relative 'mock_driver_cimi_methods'
> > 
> >  module Deltacloud::Drivers::Mock
> > 
> >    class MockDriver < Deltacloud::BaseDriver
> > 
> > -    # If the provider is set to storage, pretend to be a storage-only
> > -    # driver
> > -    def supported_collections
> > -      if api_provider == 'storage'
> > -        [:buckets]
> > -      else
> > -        DEFAULT_COLLECTIONS + [:buckets, :keys]
> > -      end
> > -    end
> > -
> >      ( REALMS = [
> >        Realm.new({
> >          :id=>'us',
> > @@ -299,11 +287,6 @@ module Deltacloud::Drivers::Mock
> >        snapshots
> >      end
> > 
> > -    def destroy_storage_snapshot(credentials, opts={})
> > -      check_credentials(credentials)
> > -      @client.destroy(:storage_snapshots, opts[:id])
> > -    end
> > -
> >      def keys(credentials, opts={})
> >        check_credentials(credentials)
> >        result = @client.build_all(Key)
> > diff --git
> > a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> > b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> > index 2dec66b..bebc45c 100644
> > --- a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> > +++ b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> > @@ -32,49 +32,6 @@ module Deltacloud::Drivers::Mock
> >        end
> >      end
> > 
> > -    def create_network(credentials, opts={})
> > -      check_credentials(credentials)
> > -      id = "#{opts[:env].send("networks_url")}/#{opts[:name]}"
> > -      net_hsh = { "id"=> id,
> > -                  "name" => opts[:name],
> > -                  "description" => opts[:description],
> > -                  "created" => Time.now,
> > -                  "state" => "STARTED",
> > -                  "access" => opts[:network_config].access,
> > -                  "bandwithLimit" =>
> opts[:network_config].bandwidth_limit,
> > -                  "trafficPriority" =>
> opts[:network_config].traffic_priority,
> > -                  "maxTrafficDelay" =>
> opts[:network_config].max_traffic_delay,
> > -                  "maxTrafficLoss"
> =>opts[:network_config].max_traffic_loss,
> > -                  "maxTrafficJitter"
> =>opts[:network_config].max_traffic_jitter,
> > -                  "routingGroup"=> { "href" =>
> opts[:routing_group].id },
> > -                  "operations" => [{"rel"=>"edit", "href"=> id},
> > -                                   {"rel"=>"delete", "href"=> id}]
> }
> > -      network =
> CIMI::Model::Network.from_json(JSON.generate(net_hsh))
> > -
> > -      @client.store_cimi(:network, network)
> > -      network
> > -    end
> > -
> > -    def delete_network(credentials, id)
> > -      check_credentials(credentials)
> > -      @client.destroy_cimi(:network, id)
> > -    end
> > -
> > -    def start_network(credentials, id)
> > -      check_credentials(credentials)
> > -      update_object_state(id, "Network", "STARTED")
> > -    end
> > -
> > -    def stop_network(credentials, id)
> > -      check_credentials(credentials)
> > -      update_object_state(id, "Network", "STOPPED")
> > -    end
> > -
> > -    def suspend_network(credentials, id)
> > -      check_credentials(credentials)
> > -      update_object_state(id, "Network", "SUSPENDED")
> > -    end
> > -
> >      def network_configurations(credentials, opts={})
> >        check_credentials(credentials)
> >        if opts[:id].nil?
> > @@ -130,43 +87,6 @@ module Deltacloud::Drivers::Mock
> >        end
> >      end
> > 
> > -    def create_vsp(credentials, opts={})
> > -      check_credentials(credentials)
> > -      id = "#{opts[:env].send("vsps_url")}/#{opts[:name]}"
> > -      vsp_hash = { "id"    => id,
> > -                    "name"  => opts[:name],
> > -                    "description" => opts[:description],
> > -                    "state" => "STARTED",
> > -                    "created" => Time.now,
> > -
> > "bandwidthReservation"=>opts[:vsp_config].bandwidth_reservation,
> > -
> "trafficPriority"=>opts[:vsp_config].traffic_priority,
> > -
> "maxTrafficDelay"=>opts[:vsp_config].max_traffic_delay,
> > -
> "maxTrafficLoss"=>opts[:vsp_config].max_traffic_loss,
> > -
> "maxTrafficJitter"=>opts[:vsp_config].max_traffic_jitter,
> > -                    "network" => {"href" => opts[:network].id},
> > -                    "operations" => [{"rel"=>"edit", "href"=> id},
> > -                                     {"rel"=>"delete", "href"=> id}]
> > -                   }
> > -      vsp = CIMI::Model::VSP.from_json(JSON.generate(vsp_hash))
> > -      @client.store_cimi(:vsp, vsp)
> > -      vsp
> > -    end
> > -
> > -    def start_vsp(credentials, id)
> > -      check_credentials(credentials)
> > -      update_object_state(id, "VSP", "STARTED")
> > -    end
> > -
> > -    def stop_vsp(credentials, id)
> > -      check_credentials(credentials)
> > -      update_object_state(id, "VSP", "STOPPED")
> > -    end
> > -
> > -    def delete_vsp(credentials, id)
> > -      check_credentials(credentials)
> > -      @client.destroy_cimi(:vsp, id)
> > -    end
> > -
> >      def vsp_configurations(credentials, opts={})
> >        check_credentials(credentials)
> >        if opts[:id].nil?
> > @@ -189,56 +109,6 @@ module Deltacloud::Drivers::Mock
> >        end
> >      end
> > 
> > -    def addresses(credentials, opts={})
> > -      check_credentials(credentials)
> > -      if opts[:id].nil?
> > -        addresses = @client.load_all_cimi(:address).map{|addr|
> > CIMI::Model::Address.from_json(addr)}
> > -        addresses.map{|addr|convert_cimi_mock_urls(:address, addr,
> > opts[:env])}.flatten
> > -      else
> > -        address =
> > CIMI::Model::Address.from_json(@client.load_cimi(:address, opts[:id]))
> > -        convert_cimi_mock_urls(:address, address, opts[:env])
> > -      end
> > -    end
> > -
> > -    def create_address(credentials, opts={})
> > -      check_credentials(credentials)
> > -      id = "#{opts[:env].send("addresses_url")}/#{opts[:name]}"
> > -      addr_hash = { "id"    => id,
> > -                    "name"  => opts[:name],
> > -                    "description" => opts[:description],
> > -                    "created" => Time.now,
> > -                    "hostName" => opts[:address_template].hostname,
> > -                    "allocation" =>
> opts[:address_template].allocation,
> > -                    "defaultGateway" =>
> opts[:address_template].default_gateway,
> > -                    "dns" => opts[:address_template].dns,
> > -                    "macAddress" =>
> opts[:address_template].mac_address,
> > -                    "protocol" => opts[:address_template].protocol,
> > -                    "mask" => opts[:address_template].mask,
> > -                    "network" => {"href" =>
> opts[:address_template].network.href},
> > -                    "operations" => [{"rel"=>"edit", "href"=> id},
> > -                                     {"rel"=>"delete", "href"=> id}]
> > -                   }
> > -      address =
> CIMI::Model::Address.from_json(JSON.generate(addr_hash))
> > -      @client.store_cimi(:address, address)
> > -      address
> > -    end
> > -
> > -    def delete_address(credentials, id)
> > -      check_credentials(credentials)
> > -      @client.destroy_cimi(:address, id)
> > -    end
> > -
> > -    def address_templates(credentials, opts={})
> > -      check_credentials(credentials)
> > -      if opts[:id].nil?
> > -        address_templates =
> > @client.load_all_cimi(:address_template).map{|addr_templ|
> > CIMI::Model::AddressTemplate.from_json(addr_templ)}
> > -
> > address_templates.map{|addr_templ|convert_cimi_mock_urls(:address_t
> > emplate, addr_templ, opts[:env])}.flatten
> > -      else
> > -        address_template =
> > CIMI::Model::AddressTemplate.from_json(@client.load_cimi(:address_tem
> > plate, opts[:id]))
> > -        convert_cimi_mock_urls(:address_template, address_template,
> > opts[:env])
> > -      end
> > -    end
> > -
> >      private
> > 
> >      def convert_cimi_mock_urls(model_name, cimi_object, context)
> > @@ -270,15 +140,6 @@ module Deltacloud::Drivers::Mock
> >        end
> >      end
> > 
> > -    def update_object_state(id, object, new_state)
> > -      klass = CIMI::Model.const_get("#{object}")
> > -      symbol = object.to_s.downcase.singularize.intern
> > -      obj = klass.from_json(@client.load_cimi(symbol, id))
> > -      obj.state = new_state
> > -      @client.store_cimi(symbol, obj)
> > -      obj
> > -    end
> > -
> >    end
> > 
> >  end
> > diff --git
> a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> > b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> > index 371e170..03c337f 100644
> > --- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> > +++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> > @@ -28,10 +28,6 @@ module Deltacloud
> > 
> >  class OpennebulaDriver < Deltacloud::BaseDriver
> > 
> > -  def supported_collections
> > -    DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
> > -  end
> > -
> > 
> > ##########################################################
> > ############
> >    # Hardware profiles
> > 
> > ##########################################################
> > ###########
> > @@ -152,8 +148,8 @@ class OpennebulaDriver < Deltacloud::BaseDriver
> >      running.to(:running)        .on( :reboot )
> >      running.to(:stopping)       .on( :stop )
> >      stopping.to(:stopped)       .automatically
> > -    running.to(:stopping)       .on( :destroy )
> > -    stopping.to(:finish)        .automatically
> > +    running.to(:shutting_down)  .on( :destroy )
> > +    shutting_down.to(:finish)   .automatically
> >    end
> > 
> >    def instances(credentials, opts=nil)
> > diff --git
> a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> > b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> > index c9ec95b..5d54d5b 100644
> > --- a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> > +++ b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> > @@ -14,9 +14,9 @@
> >  # under the License.
> >  #
> > 
> > -require 'deltacloud/base_driver'
> >  require 'openstack/compute'
> >  require 'tempfile'
> > +
> >  module Deltacloud
> >    module Drivers
> >      module Openstack
> > @@ -27,16 +27,12 @@ module Deltacloud
> >          feature :instances, :user_files
> >          feature :images, :user_name
> > 
> > -        def supported_collections
> > -          DEFAULT_COLLECTIONS - [ :storage_snapshots,
> :storage_volumes  ]
> > #+ [ :buckets ]
> > -        end
> > -
> >          define_instance_states do
> >            start.to( :pending )          .on( :create )
> >            pending.to( :running )        .automatically
> >            running.to( :running )        .on( :reboot )
> > -          running.to( :stopping )       .on( :stop )
> > -          stopping.to( :stopped )       .automatically
> > +          running.to( :shutting_down )  .on( :stop )
> > +          shutting_down.to( :stopped )  .automatically
> >            stopped.to( :finish )         .automatically
> >          end
> > 
> > @@ -140,7 +136,7 @@ module Deltacloud
> >            params[:name] = (opts[:name] && opts[:name].length>0)?
> > opts[:name] : Time.now.to_s
> >            params[:imageRef] = image_id
> >            params[:flavorRef] =  (opts[:hwp_id] &&
> opts[:hwp_id].length>0) ?
> > -                          opts[:hwp_id] :
> hardware_profiles(credentials).first.name
> > +                          opts[:hwp_id] :
> hardware_profiles(credentials).first
> >            if opts[:password] && opts[:password].length > 0
> >              params[:adminPass]=opts[:password]
> >            end
> > diff --git
> a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> > b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> > index 1b019d4..f59f832 100644
> > --- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> > +++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> > @@ -14,7 +14,6 @@
> >  # License for the specific language governing permissions and
> limitations
> >  # under the License.
> > 
> > -require 'deltacloud/base_driver'
> >  require 'cloudfiles'
> >  require 'cloudservers'
> >  require 'base64'
> > @@ -30,10 +29,6 @@ class RackspaceDriver < Deltacloud::BaseDriver
> >    feature :instances, :user_files
> >    feature :images, :user_name
> > 
> > -  def supported_collections
> > -    DEFAULT_COLLECTIONS + [ :buckets ] -
> > [ :storage_snapshots, :storage_volumes ]
> > -  end
> > -
> >    def hardware_profiles(credentials, opts = {})
> >      rs = new_client( credentials )
> >      results = []
> > @@ -194,8 +189,8 @@ class RackspaceDriver < Deltacloud::BaseDriver
> >      start.to( :pending )          .on( :create )
> >      pending.to( :running )        .automatically
> >      running.to( :running )        .on( :reboot )
> > -    running.to( :stopping )       .on( :stop )
> > -    stopping.to( :stopped )       .automatically
> > +    running.to( :shutting_down )  .on( :stop )
> > +    shutting_down.to( :stopped )  .automatically
> >      stopped.to( :finish )         .automatically
> >    end
> > 
> > diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> > b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> > index 1c96df7..f138f03 100644
> > --- a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> > +++ b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> > @@ -14,27 +14,24 @@
> >  # License for the specific language governing permissions and
> limitations
> >  # under the License.
> > 
> > -require 'deltacloud/base_driver'
> >  require 'rbovirt'
> > 
> >  module Deltacloud
> >    module Drivers
> > -    module RHEVM
> > +    module Rhevm
> > 
> > -class RHEVMDriver < Deltacloud::BaseDriver
> > +class RhevmDriver < Deltacloud::BaseDriver
> > 
> > -  def supported_collections
> > -    DEFAULT_COLLECTIONS - [:storage_snapshots]
> > -  end
> > -
> > -  feature :instances, :user_name do
> > -    constraint :max_length, 50
> > +  Sinatra::Rabbit::InstancesCollection.features do
> > +    feature :user_name, :for => :instances do
> > +      constrain :max_length, 50
> > +    end
> >    end
> > 
> >    feature :instances, :user_data
> >    feature :images, :user_name
> > 
> > -  USER_NAME_MAX =
> > feature(:instances, :user_name).constraints[:max_length]
> > +  USER_NAME_MAX =
> >
> Sinatra::Rabbit::InstancesCollection.feature(:user_name).constraints[:ma
> x_l
> > ength]
> > 
> >    # FIXME: These values are just for ilustration
> >    # Also I choosed 'SERVER' and 'DESKTOP' names
> > diff --git
> a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> > b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> > index 58f8e1b..f44336a 100644
> > --- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> > +++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> > @@ -41,17 +41,16 @@ class RimuHostingClient
> >        headers["Authorization"] = @auth
> >      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]]
> > +    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
> > +    if(res['response_type'] == "ERROR" and (
> (res['error_info']['error_class']
> > == "PermissionException") or
> >
> (res['error_info']['error_class'] ==
> > "LoginRequired") ))
> > -        raise "AuthFailure"
> > -      end
> > -      res
> > +      raise "AuthFailure"
> >      end
> > +    res
> >    end
> > 
> >    def list_images
> > @@ -82,6 +81,6 @@ class RimuHostingClient
> >    end
> >  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..8633d53 100644
> > --- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
> > +++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
> > @@ -16,7 +16,6 @@
> >  # License for the specific language governing permissions and
> limitations
> >  # under the License.
> > 
> > -require "deltacloud/base_driver"
> >  require "deltacloud/drivers/rimuhosting/rimuhosting_client"
> > 
> >  module Deltacloud
> > @@ -131,9 +130,9 @@ class RimuHostingDriver < Deltacloud::BaseDriver
> >              :owner_id => "root",
> >              :instance_profile => InstanceProfile.new("none"),
> >              :actions => instance_actions_for("RUNNING"),
> > -            :public_addresses =>
> > [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] ) ],
> > -            :launch_time =>
> inst["billing_info"]["order_date"]["iso_format"]
> > -    })
> > +            :public_addresses =>
> > [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] )],
> > +            :launch_time =>
> inst["billing_info"]["order_date"]["iso_format"]}
> > +                )
> >    end
> > 
> >    define_instance_states do
> > @@ -142,9 +141,9 @@ class RimuHostingDriver < Deltacloud::BaseDriver
> >      pending.to( :running )        .automatically
> > 
> >      running.to( :running )        .on(:reboot)
> > -    running.to( :stopping )       .on(:stop)
> > +    running.to( :shutting_down )  .on(:stop)
> > 
> > -    stopping.to( :stopped )       .automatically
> > +    shutting_down.to( :stopped )  .automatically
> > 
> >      stopped.to( :finish )         .automatically
> >    end
> > diff --git
> a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> > b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> > index 2dba02a..2e087cb 100644
> > --- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> > +++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> > @@ -19,8 +19,7 @@
> >  # https://community.vcloudexpress.terremark.com/en-
> > us/product_docs/w/wiki/d-complete-vcloud-express-api-document.aspx
> >  #
> >  # 02 May 2010
> > -#
> > -require 'deltacloud/base_driver'
> > +
> >  require 'fog'
> >  require 'excon'
> >  require 'nokogiri'
> > @@ -118,8 +117,8 @@ VAPP_STATE_MAP = { "0" =>  "PENDING", "1" =>
> > "PENDING", "2" =>  "STOPPED", "4"
> >      pending.to(:stopped)          .automatically
> >      stopped.to(:running)          .on( :start )
> >      running.to(:running)          .on( :reboot )
> > -    running.to(:stopping)         .on( :stop )
> > -    stopping.to(:stopped)         .automatically
> > +    running.to(:shutting_down)    .on( :stop )
> > +    shutting_down.to(:stopped)    .automatically
> >      stopped.to(:finish)           .on( :destroy )
> >     end
> > 
> > diff --git a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> > b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> > index e16be2f..7ac908a 100644
> > --- a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> > +++ b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> > @@ -14,18 +14,17 @@
> >  # under the License.
> >  #
> > 
> > -require 'deltacloud/base_driver'
> >  require 'rbvmomi'
> >  require 'deltacloud/drivers/vsphere/vsphere_client'
> > 
> > -module Deltacloud::Drivers::VSphere
> > +module Deltacloud::Drivers::Vsphere
> > 
> >    MAPPER_STORAGE_ROOT = File::join("/var/tmp", "deltacloud-vsphere-
> > #{ENV["USER"]}")
> > 
> > -  class VSphereDriver < Deltacloud::BaseDriver
> > +  class VsphereDriver < Deltacloud::BaseDriver
> > 
> >      include Deltacloud::Drivers::VSphere::Helper
> > -    include Deltacloud::Drivers::VSphere::FileManager
> > +    include VSphere::FileManager
> > 
> >      # You can use 'user_iso' feature to set 'user_iso' parameter when
> > creating
> >      # a new instance where this parameter can hold gzipped CDROM iso
> > which will
> > @@ -34,10 +33,6 @@ module Deltacloud::Drivers::VSphere
> >      feature :instances, :user_data
> >      feature :instances, :user_name
> > 
> > -    def supported_collections
> > -      DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
> > -    end
> > -
> >      # There is just one hardware profile where memory is measured
> using
> > maximum
> >      # memory available on ESX for virtual machines and CPU using
> maximum
> > free
> >      # CPU cores in ESX.
> > @@ -68,8 +63,8 @@ module Deltacloud::Drivers::VSphere
> >        pending.to(:stopped)        .automatically
> >        stopped.to(:running)        .on( :start )
> >        running.to(:running)        .on( :reboot )
> > -      running.to(:stopping)       .on( :stop )
> > -      stopping.to(:stopped)       .automatically
> > +      running.to(:shutting_down)  .on( :stop )
> > +      shutting_down.to(:stopped)  .automatically
> >        stopped.to(:finish)         .on( :destroy )
> >      end
> > 
> > --
> > 1.7.10
> > 
> 
> 

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

RE: [PATCH core 14/32] Core: Updated drivers to remove base_driver require and added autoloading of driver

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

> -          running.to( :stopping )       .on( :destroy )
> +          running.to( :shutting_down )  .on( :destroy )

In commit 09bfd939db278978d87539534ceda3465737acc3 David changed this
state to be consistently :stopping.
Does this mean we're reverting that and change the state consistently to
:shutting_down?

Cheers,
Dies Koper



> -----Original Message-----
> From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> Sent: Tuesday, 17 April 2012 11:40 PM
> To: dev@deltacloud.apache.org
> Subject: [PATCH core 14/32] Core: Updated drivers to remove
base_driver
> require and added autoloading of driver
> 
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/lib/deltacloud/drivers.rb                   |   48 +------
>  .../lib/deltacloud/drivers/azure/azure_driver.rb   |    4 -
>  .../lib/deltacloud/drivers/condor/condor_driver.rb |    9 +-
>  server/lib/deltacloud/drivers/ec2/ec2_driver.rb    |   18 +--
>  .../drivers/eucalyptus/eucalyptus_driver.rb        |    4 -
>  server/lib/deltacloud/drivers/features.rb          |  111
++++++++++++++++
>  .../lib/deltacloud/drivers/gogrid/gogrid_driver.rb |    6 -
>  .../lib/deltacloud/drivers/google/google_driver.rb |    3 -
>  server/lib/deltacloud/drivers/mock/mock_client.rb  |   11 --
>  server/lib/deltacloud/drivers/mock/mock_driver.rb  |   21 +--
>  .../drivers/mock/mock_driver_cimi_methods.rb       |  139
--------------------
>  .../drivers/opennebula/opennebula_driver.rb        |    8 +-
>  .../drivers/openstack/openstack_driver.rb          |   12 +-
>  .../drivers/rackspace/rackspace_driver.rb          |    9 +-
>  .../lib/deltacloud/drivers/rhevm/rhevm_driver.rb   |   17 +--
>  .../drivers/rimuhosting/rimuhosting_client.rb      |   17 ++-
>  .../drivers/rimuhosting/rimuhosting_driver.rb      |   11 +-
>  .../drivers/terremark/terremark_driver.rb          |    7 +-
>  .../deltacloud/drivers/vsphere/vsphere_driver.rb   |   15 +--
>  19 files changed, 160 insertions(+), 310 deletions(-)
>  create mode 100644 server/lib/deltacloud/drivers/features.rb
> 
> diff --git a/server/lib/deltacloud/drivers.rb
> b/server/lib/deltacloud/drivers.rb
> index dfc998d..14e7ee0 100644
> --- a/server/lib/deltacloud/drivers.rb
> +++ b/server/lib/deltacloud/drivers.rb
> @@ -13,25 +13,15 @@
>  # License for the specific language governing permissions and
limitations
>  # under the License.
> 
> -module Deltacloud
> +require_relative 'drivers/exceptions'
> +require_relative 'drivers/base_driver'
> +require_relative 'drivers/features'
> +require 'yaml'
> 
> +module Deltacloud
>    module Drivers
> 
> -    require 'yaml'
> -
> -    DEFAULT_COLLECTIONS = [
> -      :hardware_profiles,
> -      :images,
> -      :instances,
> -      :instance_states,
> -      :realms,
> -      :storage_volumes,
> -      :storage_snapshots
> -    ]
> -
> -    DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
> -
> -    def driver_config
> +    def self.driver_config
>        if Thread::current[:drivers].nil?
>          Thread::current[:drivers] = {}
>          top_srcdir = File.join(File.dirname(__FILE__), '..', '..')
> @@ -42,31 +32,5 @@ module Deltacloud
>        Thread::current[:drivers]
>      end
> 
> -    def driver_symbol
> -      (Thread.current[:driver] || DRIVER).to_sym
> -    end
> -
> -    def driver_name
> -      driver_config[:"#{driver_symbol}"][:name]
> -    end
> -
> -    def driver_class
> -      basename = driver_config[:"#{driver_symbol}"][:class] ||
> "#{driver_name}Driver"
> -      Deltacloud::Drivers.const_get(driver_name).const_get(basename)
> -    end
> -
> -    def driver_source_name
> -      File.join("deltacloud", "drivers", "#{driver_symbol}",
> "#{driver_symbol}_driver.rb")
> -    end
> -
> -    def driver_mock_source_name
> -      return File.join('deltacloud', 'drivers', "#{driver_symbol}",
> -		       "#{driver_symbol}_driver.rb") if driver_name.eql?
> 'Mock'
> -    end
> -
> -    def driver
> -      require driver_source_name
> -      @driver ||= driver_class.new
> -    end
>    end
>  end
> diff --git a/server/lib/deltacloud/drivers/azure/azure_driver.rb
> b/server/lib/deltacloud/drivers/azure/azure_driver.rb
> index 24feeb7..db2b6c6 100644
> --- a/server/lib/deltacloud/drivers/azure/azure_driver.rb
> +++ b/server/lib/deltacloud/drivers/azure/azure_driver.rb
> @@ -15,7 +15,6 @@
>  # under the License.
> 
>  #Windows Azure (WAZ) gem at http://github.com/johnnyhalife/waz-
> storage
> -require 'deltacloud/base_driver'
>  require 'waz-blobs'
> 
>  module Deltacloud
> @@ -24,9 +23,6 @@ module Deltacloud
> 
>  class AzureDriver < Deltacloud::BaseDriver
> 
> -  def supported_collections; [:buckets]
> -  end
> -
>  #--
>  # Buckets
>  #--
> diff --git a/server/lib/deltacloud/drivers/condor/condor_driver.rb
> b/server/lib/deltacloud/drivers/condor/condor_driver.rb
> index f5cb741..c139b62 100644
> --- a/server/lib/deltacloud/drivers/condor/condor_driver.rb
> +++ b/server/lib/deltacloud/drivers/condor/condor_driver.rb
> @@ -14,9 +14,6 @@
>  # under the License.
>  #
> 
> -require 'deltacloud/base_driver'
> -
> -
>  class Instance
>    def self.convert_condor_state(state_id)
>      case state_id
> @@ -44,10 +41,6 @@ module Deltacloud
>          feature :instances, :user_data
>          feature :instances, :authentication_password
> 
> -        def supported_collections
> -          DEFAULT_COLLECTIONS - [ :storage_volumes,
:storage_snapshots ]
> -        end
> -
>          CONDOR_MAPPER_DIR = ENV['CONDOR_MAPPER_DIR'] || '/var/tmp'
> 
>          def hardware_profiles(credentials, opts={})
> @@ -175,7 +168,7 @@ module Deltacloud
>            pending.to( :running )        .automatically
>            pending.to( :finish )         .on(:destroy)
>            running.to( :running )        .on( :reboot )
> -          running.to( :stopping )       .on( :destroy )
> +          running.to( :shutting_down )  .on( :destroy )
>            pending.to( :finish )         .automatically
>          end
> 
> diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> index 60e86e8..01b76b4 100644
> --- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> +++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
> @@ -14,7 +14,6 @@
>  # under the License.
>  #
> 
> -require 'deltacloud/base_driver'
>  require 'aws'
> 
>  class Instance
> @@ -29,13 +28,8 @@ end
> 
>  module Deltacloud
>    module Drivers
> -    module EC2
> -      class EC2Driver < Deltacloud::BaseDriver
> -
> -        def supported_collections
> -
> -          DEFAULT_COLLECTIONS +
> [ :keys, :buckets, :load_balancers, :addresses, :firewalls ]
> -        end
> +    module Ec2
> +      class Ec2Driver < Deltacloud::BaseDriver
> 
>          feature :instances, :user_data
>          feature :instances, :authentication_key
> @@ -127,8 +121,7 @@ module Deltacloud
>            stopped.to( :running )        .on( :start )
>            running.to( :running )        .on( :reboot )
>            running.to( :stopping )       .on( :stop )
> -          stopping.to(:stopped)         .automatically
> -          stopping.to(:finish)          .automatically
> +          shutting_down.to( :stopped )  .automatically
>            stopped.to( :finish )         .automatically
>          end
> 
> @@ -413,9 +406,7 @@ module Deltacloud
>            safely do
>              s3_bucket = s3_client.bucket(opts['bucket'])
>              if(opts[:id])
> -              s3_key = s3_bucket.key(opts[:id], true)
> -              raise "Blob #{opts[:id]} in Bucket #{opts['bucket']}
NotFound"
> unless s3_key.exists?
> -              blobs << convert_object(s3_key)
> +              blobs << convert_object(s3_bucket.key(opts[:id], true))
>              else
>                s3_bucket.keys({}, true).each do |s3_object|
>                  blobs << convert_object(s3_object)
> @@ -471,7 +462,6 @@ module Deltacloud
>            blob_meta = {}
>            safely do
>              the_blob =
s3_client.bucket(opts['bucket']).key(opts[:id], true)
> -            raise "Blob #{opts[:id]} in Bucket #{opts['bucket']}
NotFound" unless
> the_blob.exists?
>              blob_meta = the_blob.meta_headers
>            end
>          end
> diff --git
a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> index 2270178..54c1eed 100644
> --- a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> +++ b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
> @@ -21,10 +21,6 @@ module Deltacloud
>      module Eucalyptus
>        class EucalyptusDriver < EC2::EC2Driver
> 
> -        def supported_collections
> -          DEFAULT_COLLECTIONS + [ :keys, :buckets, :addresses,
:firewalls ]
> -        end
> -
>          feature :instances, :user_data
>          feature :instances, :authentication_key
>          feature :instances, :firewalls
> diff --git a/server/lib/deltacloud/drivers/features.rb
> b/server/lib/deltacloud/drivers/features.rb
> new file mode 100644
> index 0000000..01d8656
> --- /dev/null
> +++ b/server/lib/deltacloud/drivers/features.rb
> @@ -0,0 +1,111 @@
> +# Licensed to the Apache Software Foundation (ASF) under one or more
> +# contributor license agreements.  See the NOTICE file distributed
with
> +# this work for additional information regarding copyright ownership.
The
> +# ASF licenses this file to you under the Apache License, Version 2.0
(the
> +# "License"); you may not use this file except in compliance with the
> +# License.  You may obtain a copy of the License at
> +#
> +#       http://www.apache.org/licenses/LICENSE-2.0
> +#
> +# Unless required by applicable law or agreed to in writing, software
> +# distributed under the License is distributed on an "AS IS" BASIS,
> WITHOUT
> +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> See the
> +# License for the specific language governing permissions and
limitations
> +# under the License.
> +
> +module Deltacloud
> +  module InstanceFeatures
> +
> +    def self.included(k)
> +      current_features = features
> +      k.instance_eval do
> +        features(&current_features)
> +      end
> +    end
> +
> +    def self.features(&block)
> +      block_given? ? @features = block : @features || Proc.new{}
> +    end
> +
> +    features do
> +
> +      feature :user_name, :for => :instances do
> +        description "Allow to set user-defined name for the instance"
> +        operation :create do
> +          param :name, :string, :optional
> +        end
> +      end
> +
> +      feature :user_data, :for => :instances do
> +        description "Allow to pass user-defined data into the
instance"
> +        operation :create do
> +          param :user_data, :string, :optional
> +        end
> +      end
> +
> +      feature :user_iso, :for => :instances do
> +        description  "Base64 encoded gzipped ISO file will be
accessible as CD-
> ROM drive in instance"
> +        operation :create do
> +          param :user_iso, :string, :optional
> +        end
> +      end
> +
> +      feature :firewalls, :for => :instances do
> +        description "Put instance in one or more firewalls (security
groups) on
> launch"
> +        operation :create do
> +          param :firewalls, :array, :optional, nil, "Array of
firewall ID strings"
> +          "Array of firewall (security group) id"
> +        end
> +      end
> +
> +      feature :authentication_key, :for => :instances do
> +        operation :create do
> +          param :keyname, :string,  :optional, [], "Key
authentification
> method"
> +        end
> +        operation :show do
> +        end
> +      end
> +
> +      feature :authentication_password, :for => :instances do
> +        operation :create do
> +          param :password, :string, :optional
> +        end
> +      end
> +
> +      feature :hardware_profiles, :for => :instances do
> +        description "Size instances according to changes to a
hardware
> profile"
> +        # The parameters are filled in from the hardware profiles
> +      end
> +
> +      feature :register_to_load_balancer, :for => :instances do
> +        description "Register instance to load balancer"
> +        operation :create do
> +          param :load_balancer_id, :string, :optional
> +        end
> +      end
> +
> +      feature :instance_count, :for => :instances do
> +        description "Number of instances to be launch with at once"
> +        operation :create do
> +          param :instance_count,  :string,  :optional
> +        end
> +      end
> +
> +      feature :attach_snapshot, :for => :instances do
> +        description "Attach an snapshot to instance on create"
> +        operation :create do
> +          param :snapshot_id,  :string,  :optional
> +          param :device_name,  :string,  :optional
> +        end
> +      end
> +
> +      feature :sandboxing, :for => :instances do
> +        description "Allow lanuching sandbox images"
> +        operation :create do
> +          param :sandbox, :string,  :optional
> +        end
> +      end
> +    end
> +
> +  end
> +end
> diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> index 285f58f..2a83c24 100644
> --- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> +++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
> @@ -14,7 +14,6 @@
>  # License for the specific language governing permissions and
limitations
>  # under the License.
> 
> -require 'deltacloud/base_driver'
>  require 'deltacloud/drivers/gogrid/gogrid_client'
> 
>  class Instance
> @@ -61,11 +60,6 @@ class GogridDriver < Deltacloud::BaseDriver
>      @hardware_profiles
>    end
> 
> -  def supported_collections
> -    DEFAULT_COLLECTIONS.reject! { |c|
> [ :storage_volumes, :storage_snapshots ].include?(c) }
> -    DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
> -  end
> -
>    def images(credentials, opts=nil)
>      imgs = []
>      if opts and opts[:id]
> diff --git a/server/lib/deltacloud/drivers/google/google_driver.rb
> b/server/lib/deltacloud/drivers/google/google_driver.rb
> index 2ffb5f8..8bc6f25 100644
> --- a/server/lib/deltacloud/drivers/google/google_driver.rb
> +++ b/server/lib/deltacloud/drivers/google/google_driver.rb
> @@ -21,9 +21,6 @@ module Deltacloud
> 
>  class GoogleDriver < Deltacloud::BaseDriver
> 
> -  def supported_collections; [:buckets]
> -  end
> -
>    feature :buckets, :bucket_location
> 
>  #--
> diff --git a/server/lib/deltacloud/drivers/mock/mock_client.rb
> b/server/lib/deltacloud/drivers/mock/mock_client.rb
> index 94c56af..248cc49 100644
> --- a/server/lib/deltacloud/drivers/mock/mock_client.rb
> +++ b/server/lib/deltacloud/drivers/mock/mock_client.rb
> @@ -91,17 +91,6 @@ module Deltacloud::Drivers::Mock
>        FileUtils.rm(fname) if File::exists?(fname)
>      end
> 
> -    def store_cimi(collection, obj)
> -      raise "Why no obj.name?" unless obj.name
> -      File::open(cimi_file(collection, obj.name), "w") { |f|
> f.write(obj.to_json) }
> -    end
> -
> -    def destroy_cimi(collection, id)
> -      fname = cimi_file(collection, id)
> -      raise "No such object: #{id} in #{collection} collection"
unless
> File::exists?(fname)
> -      FileUtils.rm(fname)
> -    end
> -
>      def load_all_cimi(model_name)
>          model_files = Dir[File::join(cimi_dir(model_name), "*.json")]
>          model_files.map{|f| File.read(f)}
> diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb
> b/server/lib/deltacloud/drivers/mock/mock_driver.rb
> index b58872c..15f06fb 100644
> --- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
> +++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
> @@ -14,28 +14,16 @@
>  # License for the specific language governing permissions and
limitations
>  # under the License.
> 
> -
>  require 'yaml'
>  require 'base64'
>  require 'etc'
> -require 'deltacloud/base_driver'
> -require 'deltacloud/drivers/mock/mock_client'
> -require 'deltacloud/drivers/mock/mock_driver_cimi_methods'
> +require_relative 'mock_client'
> +require_relative 'mock_driver_cimi_methods'
> 
>  module Deltacloud::Drivers::Mock
> 
>    class MockDriver < Deltacloud::BaseDriver
> 
> -    # If the provider is set to storage, pretend to be a storage-only
> -    # driver
> -    def supported_collections
> -      if api_provider == 'storage'
> -        [:buckets]
> -      else
> -        DEFAULT_COLLECTIONS + [:buckets, :keys]
> -      end
> -    end
> -
>      ( REALMS = [
>        Realm.new({
>          :id=>'us',
> @@ -299,11 +287,6 @@ module Deltacloud::Drivers::Mock
>        snapshots
>      end
> 
> -    def destroy_storage_snapshot(credentials, opts={})
> -      check_credentials(credentials)
> -      @client.destroy(:storage_snapshots, opts[:id])
> -    end
> -
>      def keys(credentials, opts={})
>        check_credentials(credentials)
>        result = @client.build_all(Key)
> diff --git
> a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> index 2dec66b..bebc45c 100644
> --- a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> +++ b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
> @@ -32,49 +32,6 @@ module Deltacloud::Drivers::Mock
>        end
>      end
> 
> -    def create_network(credentials, opts={})
> -      check_credentials(credentials)
> -      id = "#{opts[:env].send("networks_url")}/#{opts[:name]}"
> -      net_hsh = { "id"=> id,
> -                  "name" => opts[:name],
> -                  "description" => opts[:description],
> -                  "created" => Time.now,
> -                  "state" => "STARTED",
> -                  "access" => opts[:network_config].access,
> -                  "bandwithLimit" =>
opts[:network_config].bandwidth_limit,
> -                  "trafficPriority" =>
opts[:network_config].traffic_priority,
> -                  "maxTrafficDelay" =>
opts[:network_config].max_traffic_delay,
> -                  "maxTrafficLoss"
=>opts[:network_config].max_traffic_loss,
> -                  "maxTrafficJitter"
=>opts[:network_config].max_traffic_jitter,
> -                  "routingGroup"=> { "href" =>
opts[:routing_group].id },
> -                  "operations" => [{"rel"=>"edit", "href"=> id},
> -                                   {"rel"=>"delete", "href"=> id}]
}
> -      network =
CIMI::Model::Network.from_json(JSON.generate(net_hsh))
> -
> -      @client.store_cimi(:network, network)
> -      network
> -    end
> -
> -    def delete_network(credentials, id)
> -      check_credentials(credentials)
> -      @client.destroy_cimi(:network, id)
> -    end
> -
> -    def start_network(credentials, id)
> -      check_credentials(credentials)
> -      update_object_state(id, "Network", "STARTED")
> -    end
> -
> -    def stop_network(credentials, id)
> -      check_credentials(credentials)
> -      update_object_state(id, "Network", "STOPPED")
> -    end
> -
> -    def suspend_network(credentials, id)
> -      check_credentials(credentials)
> -      update_object_state(id, "Network", "SUSPENDED")
> -    end
> -
>      def network_configurations(credentials, opts={})
>        check_credentials(credentials)
>        if opts[:id].nil?
> @@ -130,43 +87,6 @@ module Deltacloud::Drivers::Mock
>        end
>      end
> 
> -    def create_vsp(credentials, opts={})
> -      check_credentials(credentials)
> -      id = "#{opts[:env].send("vsps_url")}/#{opts[:name]}"
> -      vsp_hash = { "id"    => id,
> -                    "name"  => opts[:name],
> -                    "description" => opts[:description],
> -                    "state" => "STARTED",
> -                    "created" => Time.now,
> -
> "bandwidthReservation"=>opts[:vsp_config].bandwidth_reservation,
> -
"trafficPriority"=>opts[:vsp_config].traffic_priority,
> -
"maxTrafficDelay"=>opts[:vsp_config].max_traffic_delay,
> -
"maxTrafficLoss"=>opts[:vsp_config].max_traffic_loss,
> -
"maxTrafficJitter"=>opts[:vsp_config].max_traffic_jitter,
> -                    "network" => {"href" => opts[:network].id},
> -                    "operations" => [{"rel"=>"edit", "href"=> id},
> -                                     {"rel"=>"delete", "href"=> id}]
> -                   }
> -      vsp = CIMI::Model::VSP.from_json(JSON.generate(vsp_hash))
> -      @client.store_cimi(:vsp, vsp)
> -      vsp
> -    end
> -
> -    def start_vsp(credentials, id)
> -      check_credentials(credentials)
> -      update_object_state(id, "VSP", "STARTED")
> -    end
> -
> -    def stop_vsp(credentials, id)
> -      check_credentials(credentials)
> -      update_object_state(id, "VSP", "STOPPED")
> -    end
> -
> -    def delete_vsp(credentials, id)
> -      check_credentials(credentials)
> -      @client.destroy_cimi(:vsp, id)
> -    end
> -
>      def vsp_configurations(credentials, opts={})
>        check_credentials(credentials)
>        if opts[:id].nil?
> @@ -189,56 +109,6 @@ module Deltacloud::Drivers::Mock
>        end
>      end
> 
> -    def addresses(credentials, opts={})
> -      check_credentials(credentials)
> -      if opts[:id].nil?
> -        addresses = @client.load_all_cimi(:address).map{|addr|
> CIMI::Model::Address.from_json(addr)}
> -        addresses.map{|addr|convert_cimi_mock_urls(:address, addr,
> opts[:env])}.flatten
> -      else
> -        address =
> CIMI::Model::Address.from_json(@client.load_cimi(:address, opts[:id]))
> -        convert_cimi_mock_urls(:address, address, opts[:env])
> -      end
> -    end
> -
> -    def create_address(credentials, opts={})
> -      check_credentials(credentials)
> -      id = "#{opts[:env].send("addresses_url")}/#{opts[:name]}"
> -      addr_hash = { "id"    => id,
> -                    "name"  => opts[:name],
> -                    "description" => opts[:description],
> -                    "created" => Time.now,
> -                    "hostName" => opts[:address_template].hostname,
> -                    "allocation" =>
opts[:address_template].allocation,
> -                    "defaultGateway" =>
opts[:address_template].default_gateway,
> -                    "dns" => opts[:address_template].dns,
> -                    "macAddress" =>
opts[:address_template].mac_address,
> -                    "protocol" => opts[:address_template].protocol,
> -                    "mask" => opts[:address_template].mask,
> -                    "network" => {"href" =>
opts[:address_template].network.href},
> -                    "operations" => [{"rel"=>"edit", "href"=> id},
> -                                     {"rel"=>"delete", "href"=> id}]
> -                   }
> -      address =
CIMI::Model::Address.from_json(JSON.generate(addr_hash))
> -      @client.store_cimi(:address, address)
> -      address
> -    end
> -
> -    def delete_address(credentials, id)
> -      check_credentials(credentials)
> -      @client.destroy_cimi(:address, id)
> -    end
> -
> -    def address_templates(credentials, opts={})
> -      check_credentials(credentials)
> -      if opts[:id].nil?
> -        address_templates =
> @client.load_all_cimi(:address_template).map{|addr_templ|
> CIMI::Model::AddressTemplate.from_json(addr_templ)}
> -
> address_templates.map{|addr_templ|convert_cimi_mock_urls(:address_t
> emplate, addr_templ, opts[:env])}.flatten
> -      else
> -        address_template =
> CIMI::Model::AddressTemplate.from_json(@client.load_cimi(:address_tem
> plate, opts[:id]))
> -        convert_cimi_mock_urls(:address_template, address_template,
> opts[:env])
> -      end
> -    end
> -
>      private
> 
>      def convert_cimi_mock_urls(model_name, cimi_object, context)
> @@ -270,15 +140,6 @@ module Deltacloud::Drivers::Mock
>        end
>      end
> 
> -    def update_object_state(id, object, new_state)
> -      klass = CIMI::Model.const_get("#{object}")
> -      symbol = object.to_s.downcase.singularize.intern
> -      obj = klass.from_json(@client.load_cimi(symbol, id))
> -      obj.state = new_state
> -      @client.store_cimi(symbol, obj)
> -      obj
> -    end
> -
>    end
> 
>  end
> diff --git
a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> index 371e170..03c337f 100644
> --- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> +++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
> @@ -28,10 +28,6 @@ module Deltacloud
> 
>  class OpennebulaDriver < Deltacloud::BaseDriver
> 
> -  def supported_collections
> -    DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
> -  end
> -
> 
> ##########################################################
> ############
>    # Hardware profiles
> 
> ##########################################################
> ###########
> @@ -152,8 +148,8 @@ class OpennebulaDriver < Deltacloud::BaseDriver
>      running.to(:running)        .on( :reboot )
>      running.to(:stopping)       .on( :stop )
>      stopping.to(:stopped)       .automatically
> -    running.to(:stopping)       .on( :destroy )
> -    stopping.to(:finish)        .automatically
> +    running.to(:shutting_down)  .on( :destroy )
> +    shutting_down.to(:finish)   .automatically
>    end
> 
>    def instances(credentials, opts=nil)
> diff --git
a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> index c9ec95b..5d54d5b 100644
> --- a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> +++ b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
> @@ -14,9 +14,9 @@
>  # under the License.
>  #
> 
> -require 'deltacloud/base_driver'
>  require 'openstack/compute'
>  require 'tempfile'
> +
>  module Deltacloud
>    module Drivers
>      module Openstack
> @@ -27,16 +27,12 @@ module Deltacloud
>          feature :instances, :user_files
>          feature :images, :user_name
> 
> -        def supported_collections
> -          DEFAULT_COLLECTIONS - [ :storage_snapshots,
:storage_volumes  ]
> #+ [ :buckets ]
> -        end
> -
>          define_instance_states do
>            start.to( :pending )          .on( :create )
>            pending.to( :running )        .automatically
>            running.to( :running )        .on( :reboot )
> -          running.to( :stopping )       .on( :stop )
> -          stopping.to( :stopped )       .automatically
> +          running.to( :shutting_down )  .on( :stop )
> +          shutting_down.to( :stopped )  .automatically
>            stopped.to( :finish )         .automatically
>          end
> 
> @@ -140,7 +136,7 @@ module Deltacloud
>            params[:name] = (opts[:name] && opts[:name].length>0)?
> opts[:name] : Time.now.to_s
>            params[:imageRef] = image_id
>            params[:flavorRef] =  (opts[:hwp_id] &&
opts[:hwp_id].length>0) ?
> -                          opts[:hwp_id] :
hardware_profiles(credentials).first.name
> +                          opts[:hwp_id] :
hardware_profiles(credentials).first
>            if opts[:password] && opts[:password].length > 0
>              params[:adminPass]=opts[:password]
>            end
> diff --git
a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> index 1b019d4..f59f832 100644
> --- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> +++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
> @@ -14,7 +14,6 @@
>  # License for the specific language governing permissions and
limitations
>  # under the License.
> 
> -require 'deltacloud/base_driver'
>  require 'cloudfiles'
>  require 'cloudservers'
>  require 'base64'
> @@ -30,10 +29,6 @@ class RackspaceDriver < Deltacloud::BaseDriver
>    feature :instances, :user_files
>    feature :images, :user_name
> 
> -  def supported_collections
> -    DEFAULT_COLLECTIONS + [ :buckets ] -
> [ :storage_snapshots, :storage_volumes ]
> -  end
> -
>    def hardware_profiles(credentials, opts = {})
>      rs = new_client( credentials )
>      results = []
> @@ -194,8 +189,8 @@ class RackspaceDriver < Deltacloud::BaseDriver
>      start.to( :pending )          .on( :create )
>      pending.to( :running )        .automatically
>      running.to( :running )        .on( :reboot )
> -    running.to( :stopping )       .on( :stop )
> -    stopping.to( :stopped )       .automatically
> +    running.to( :shutting_down )  .on( :stop )
> +    shutting_down.to( :stopped )  .automatically
>      stopped.to( :finish )         .automatically
>    end
> 
> diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> index 1c96df7..f138f03 100644
> --- a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> +++ b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
> @@ -14,27 +14,24 @@
>  # License for the specific language governing permissions and
limitations
>  # under the License.
> 
> -require 'deltacloud/base_driver'
>  require 'rbovirt'
> 
>  module Deltacloud
>    module Drivers
> -    module RHEVM
> +    module Rhevm
> 
> -class RHEVMDriver < Deltacloud::BaseDriver
> +class RhevmDriver < Deltacloud::BaseDriver
> 
> -  def supported_collections
> -    DEFAULT_COLLECTIONS - [:storage_snapshots]
> -  end
> -
> -  feature :instances, :user_name do
> -    constraint :max_length, 50
> +  Sinatra::Rabbit::InstancesCollection.features do
> +    feature :user_name, :for => :instances do
> +      constrain :max_length, 50
> +    end
>    end
> 
>    feature :instances, :user_data
>    feature :images, :user_name
> 
> -  USER_NAME_MAX =
> feature(:instances, :user_name).constraints[:max_length]
> +  USER_NAME_MAX =
>
Sinatra::Rabbit::InstancesCollection.feature(:user_name).constraints[:ma
x_l
> ength]
> 
>    # FIXME: These values are just for ilustration
>    # Also I choosed 'SERVER' and 'DESKTOP' names
> diff --git
a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> index 58f8e1b..f44336a 100644
> --- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> +++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
> @@ -41,17 +41,16 @@ class RimuHostingClient
>        headers["Authorization"] = @auth
>      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]]
> +    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
> +    if(res['response_type'] == "ERROR" and (
(res['error_info']['error_class']
> == "PermissionException") or
>
(res['error_info']['error_class'] ==
> "LoginRequired") ))
> -        raise "AuthFailure"
> -      end
> -      res
> +      raise "AuthFailure"
>      end
> +    res
>    end
> 
>    def list_images
> @@ -82,6 +81,6 @@ class RimuHostingClient
>    end
>  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..8633d53 100644
> --- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
> +++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
> @@ -16,7 +16,6 @@
>  # License for the specific language governing permissions and
limitations
>  # under the License.
> 
> -require "deltacloud/base_driver"
>  require "deltacloud/drivers/rimuhosting/rimuhosting_client"
> 
>  module Deltacloud
> @@ -131,9 +130,9 @@ class RimuHostingDriver < Deltacloud::BaseDriver
>              :owner_id => "root",
>              :instance_profile => InstanceProfile.new("none"),
>              :actions => instance_actions_for("RUNNING"),
> -            :public_addresses =>
> [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] ) ],
> -            :launch_time =>
inst["billing_info"]["order_date"]["iso_format"]
> -    })
> +            :public_addresses =>
> [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] )],
> +            :launch_time =>
inst["billing_info"]["order_date"]["iso_format"]}
> +                )
>    end
> 
>    define_instance_states do
> @@ -142,9 +141,9 @@ class RimuHostingDriver < Deltacloud::BaseDriver
>      pending.to( :running )        .automatically
> 
>      running.to( :running )        .on(:reboot)
> -    running.to( :stopping )       .on(:stop)
> +    running.to( :shutting_down )  .on(:stop)
> 
> -    stopping.to( :stopped )       .automatically
> +    shutting_down.to( :stopped )  .automatically
> 
>      stopped.to( :finish )         .automatically
>    end
> diff --git
a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> index 2dba02a..2e087cb 100644
> --- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> +++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
> @@ -19,8 +19,7 @@
>  # https://community.vcloudexpress.terremark.com/en-
> us/product_docs/w/wiki/d-complete-vcloud-express-api-document.aspx
>  #
>  # 02 May 2010
> -#
> -require 'deltacloud/base_driver'
> +
>  require 'fog'
>  require 'excon'
>  require 'nokogiri'
> @@ -118,8 +117,8 @@ VAPP_STATE_MAP = { "0" =>  "PENDING", "1" =>
> "PENDING", "2" =>  "STOPPED", "4"
>      pending.to(:stopped)          .automatically
>      stopped.to(:running)          .on( :start )
>      running.to(:running)          .on( :reboot )
> -    running.to(:stopping)         .on( :stop )
> -    stopping.to(:stopped)         .automatically
> +    running.to(:shutting_down)    .on( :stop )
> +    shutting_down.to(:stopped)    .automatically
>      stopped.to(:finish)           .on( :destroy )
>     end
> 
> diff --git a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> index e16be2f..7ac908a 100644
> --- a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> +++ b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
> @@ -14,18 +14,17 @@
>  # under the License.
>  #
> 
> -require 'deltacloud/base_driver'
>  require 'rbvmomi'
>  require 'deltacloud/drivers/vsphere/vsphere_client'
> 
> -module Deltacloud::Drivers::VSphere
> +module Deltacloud::Drivers::Vsphere
> 
>    MAPPER_STORAGE_ROOT = File::join("/var/tmp", "deltacloud-vsphere-
> #{ENV["USER"]}")
> 
> -  class VSphereDriver < Deltacloud::BaseDriver
> +  class VsphereDriver < Deltacloud::BaseDriver
> 
>      include Deltacloud::Drivers::VSphere::Helper
> -    include Deltacloud::Drivers::VSphere::FileManager
> +    include VSphere::FileManager
> 
>      # You can use 'user_iso' feature to set 'user_iso' parameter when
> creating
>      # a new instance where this parameter can hold gzipped CDROM iso
> which will
> @@ -34,10 +33,6 @@ module Deltacloud::Drivers::VSphere
>      feature :instances, :user_data
>      feature :instances, :user_name
> 
> -    def supported_collections
> -      DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
> -    end
> -
>      # There is just one hardware profile where memory is measured
using
> maximum
>      # memory available on ESX for virtual machines and CPU using
maximum
> free
>      # CPU cores in ESX.
> @@ -68,8 +63,8 @@ module Deltacloud::Drivers::VSphere
>        pending.to(:stopped)        .automatically
>        stopped.to(:running)        .on( :start )
>        running.to(:running)        .on( :reboot )
> -      running.to(:stopping)       .on( :stop )
> -      stopping.to(:stopped)       .automatically
> +      running.to(:shutting_down)  .on( :stop )
> +      shutting_down.to(:stopped)  .automatically
>        stopped.to(:finish)         .on( :destroy )
>      end
> 
> --
> 1.7.10
> 



[PATCH core 14/32] Core: Updated drivers to remove base_driver require and added autoloading of driver

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


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

diff --git a/server/lib/deltacloud/drivers.rb b/server/lib/deltacloud/drivers.rb
index dfc998d..14e7ee0 100644
--- a/server/lib/deltacloud/drivers.rb
+++ b/server/lib/deltacloud/drivers.rb
@@ -13,25 +13,15 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-module Deltacloud
+require_relative 'drivers/exceptions'
+require_relative 'drivers/base_driver'
+require_relative 'drivers/features'
+require 'yaml'
 
+module Deltacloud
   module Drivers
 
-    require 'yaml'
-
-    DEFAULT_COLLECTIONS = [
-      :hardware_profiles,
-      :images,
-      :instances,
-      :instance_states,
-      :realms,
-      :storage_volumes,
-      :storage_snapshots
-    ]
-
-    DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
-
-    def driver_config
+    def self.driver_config
       if Thread::current[:drivers].nil?
         Thread::current[:drivers] = {}
         top_srcdir = File.join(File.dirname(__FILE__), '..', '..')
@@ -42,31 +32,5 @@ module Deltacloud
       Thread::current[:drivers]
     end
 
-    def driver_symbol
-      (Thread.current[:driver] || DRIVER).to_sym
-    end
-
-    def driver_name
-      driver_config[:"#{driver_symbol}"][:name]
-    end
-
-    def driver_class
-      basename = driver_config[:"#{driver_symbol}"][:class] || "#{driver_name}Driver"
-      Deltacloud::Drivers.const_get(driver_name).const_get(basename)
-    end
-
-    def driver_source_name
-      File.join("deltacloud", "drivers", "#{driver_symbol}", "#{driver_symbol}_driver.rb")
-    end
-
-    def driver_mock_source_name
-      return File.join('deltacloud', 'drivers', "#{driver_symbol}",
-		       "#{driver_symbol}_driver.rb") if driver_name.eql? 'Mock'
-    end
-
-    def driver
-      require driver_source_name
-      @driver ||= driver_class.new
-    end
   end
 end
diff --git a/server/lib/deltacloud/drivers/azure/azure_driver.rb b/server/lib/deltacloud/drivers/azure/azure_driver.rb
index 24feeb7..db2b6c6 100644
--- a/server/lib/deltacloud/drivers/azure/azure_driver.rb
+++ b/server/lib/deltacloud/drivers/azure/azure_driver.rb
@@ -15,7 +15,6 @@
 # under the License.
 
 #Windows Azure (WAZ) gem at http://github.com/johnnyhalife/waz-storage
-require 'deltacloud/base_driver'
 require 'waz-blobs'
 
 module Deltacloud
@@ -24,9 +23,6 @@ module Deltacloud
 
 class AzureDriver < Deltacloud::BaseDriver
 
-  def supported_collections; [:buckets]
-  end
-
 #--
 # Buckets
 #--
diff --git a/server/lib/deltacloud/drivers/condor/condor_driver.rb b/server/lib/deltacloud/drivers/condor/condor_driver.rb
index f5cb741..c139b62 100644
--- a/server/lib/deltacloud/drivers/condor/condor_driver.rb
+++ b/server/lib/deltacloud/drivers/condor/condor_driver.rb
@@ -14,9 +14,6 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
-
-
 class Instance
   def self.convert_condor_state(state_id)
     case state_id
@@ -44,10 +41,6 @@ module Deltacloud
         feature :instances, :user_data
         feature :instances, :authentication_password
 
-        def supported_collections
-          DEFAULT_COLLECTIONS - [ :storage_volumes, :storage_snapshots ]
-        end
-
         CONDOR_MAPPER_DIR = ENV['CONDOR_MAPPER_DIR'] || '/var/tmp'
 
         def hardware_profiles(credentials, opts={})
@@ -175,7 +168,7 @@ module Deltacloud
           pending.to( :running )        .automatically
           pending.to( :finish )         .on(:destroy)
           running.to( :running )        .on( :reboot )
-          running.to( :stopping )       .on( :destroy )
+          running.to( :shutting_down )  .on( :destroy )
           pending.to( :finish )         .automatically
         end
 
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index 60e86e8..01b76b4 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -14,7 +14,6 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'aws'
 
 class Instance
@@ -29,13 +28,8 @@ end
 
 module Deltacloud
   module Drivers
-    module EC2
-      class EC2Driver < Deltacloud::BaseDriver
-
-        def supported_collections
-
-          DEFAULT_COLLECTIONS + [ :keys, :buckets, :load_balancers, :addresses, :firewalls ]
-        end
+    module Ec2
+      class Ec2Driver < Deltacloud::BaseDriver
 
         feature :instances, :user_data
         feature :instances, :authentication_key
@@ -127,8 +121,7 @@ module Deltacloud
           stopped.to( :running )        .on( :start )
           running.to( :running )        .on( :reboot )
           running.to( :stopping )       .on( :stop )
-          stopping.to(:stopped)         .automatically
-          stopping.to(:finish)          .automatically
+          shutting_down.to( :stopped )  .automatically
           stopped.to( :finish )         .automatically
         end
 
@@ -413,9 +406,7 @@ module Deltacloud
           safely do
             s3_bucket = s3_client.bucket(opts['bucket'])
             if(opts[:id])
-              s3_key = s3_bucket.key(opts[:id], true)
-              raise "Blob #{opts[:id]} in Bucket #{opts['bucket']} NotFound" unless s3_key.exists?
-              blobs << convert_object(s3_key)
+              blobs << convert_object(s3_bucket.key(opts[:id], true))
             else
               s3_bucket.keys({}, true).each do |s3_object|
                 blobs << convert_object(s3_object)
@@ -471,7 +462,6 @@ module Deltacloud
           blob_meta = {}
           safely do
             the_blob = s3_client.bucket(opts['bucket']).key(opts[:id], true)
-            raise "Blob #{opts[:id]} in Bucket #{opts['bucket']} NotFound" unless the_blob.exists?
             blob_meta = the_blob.meta_headers
           end
         end
diff --git a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
index 2270178..54c1eed 100644
--- a/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
+++ b/server/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb
@@ -21,10 +21,6 @@ module Deltacloud
     module Eucalyptus
       class EucalyptusDriver < EC2::EC2Driver
 
-        def supported_collections
-          DEFAULT_COLLECTIONS + [ :keys, :buckets, :addresses, :firewalls ]
-        end
-
         feature :instances, :user_data
         feature :instances, :authentication_key
         feature :instances, :firewalls
diff --git a/server/lib/deltacloud/drivers/features.rb b/server/lib/deltacloud/drivers/features.rb
new file mode 100644
index 0000000..01d8656
--- /dev/null
+++ b/server/lib/deltacloud/drivers/features.rb
@@ -0,0 +1,111 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+  module InstanceFeatures
+
+    def self.included(k)
+      current_features = features
+      k.instance_eval do
+        features(&current_features)
+      end
+    end
+
+    def self.features(&block)
+      block_given? ? @features = block : @features || Proc.new{}
+    end
+
+    features do
+
+      feature :user_name, :for => :instances do
+        description "Allow to set user-defined name for the instance"
+        operation :create do
+          param :name, :string, :optional
+        end
+      end
+
+      feature :user_data, :for => :instances do
+        description "Allow to pass user-defined data into the instance"
+        operation :create do
+          param :user_data, :string, :optional
+        end
+      end
+
+      feature :user_iso, :for => :instances do
+        description  "Base64 encoded gzipped ISO file will be accessible as CD-ROM drive in instance"
+        operation :create do
+          param :user_iso, :string, :optional
+        end
+      end
+
+      feature :firewalls, :for => :instances do
+        description "Put instance in one or more firewalls (security groups) on launch"
+        operation :create do
+          param :firewalls, :array, :optional, nil, "Array of firewall ID strings"
+          "Array of firewall (security group) id"
+        end
+      end
+
+      feature :authentication_key, :for => :instances do
+        operation :create do
+          param :keyname, :string,  :optional, [], "Key authentification method"
+        end
+        operation :show do
+        end
+      end
+
+      feature :authentication_password, :for => :instances do
+        operation :create do
+          param :password, :string, :optional
+        end
+      end
+
+      feature :hardware_profiles, :for => :instances do
+        description "Size instances according to changes to a hardware profile"
+        # The parameters are filled in from the hardware profiles
+      end
+
+      feature :register_to_load_balancer, :for => :instances do
+        description "Register instance to load balancer"
+        operation :create do
+          param :load_balancer_id, :string, :optional
+        end
+      end
+
+      feature :instance_count, :for => :instances do
+        description "Number of instances to be launch with at once"
+        operation :create do
+          param :instance_count,  :string,  :optional
+        end
+      end
+
+      feature :attach_snapshot, :for => :instances do
+        description "Attach an snapshot to instance on create"
+        operation :create do
+          param :snapshot_id,  :string,  :optional
+          param :device_name,  :string,  :optional
+        end
+      end
+
+      feature :sandboxing, :for => :instances do
+        description "Allow lanuching sandbox images"
+        operation :create do
+          param :sandbox, :string,  :optional
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
index 285f58f..2a83c24 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
@@ -14,7 +14,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/base_driver'
 require 'deltacloud/drivers/gogrid/gogrid_client'
 
 class Instance
@@ -61,11 +60,6 @@ class GogridDriver < Deltacloud::BaseDriver
     @hardware_profiles
   end
 
-  def supported_collections
-    DEFAULT_COLLECTIONS.reject! { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
-    DEFAULT_COLLECTIONS + [ :keys, :load_balancers ]
-  end
-
   def images(credentials, opts=nil)
     imgs = []
     if opts and opts[:id]
diff --git a/server/lib/deltacloud/drivers/google/google_driver.rb b/server/lib/deltacloud/drivers/google/google_driver.rb
index 2ffb5f8..8bc6f25 100644
--- a/server/lib/deltacloud/drivers/google/google_driver.rb
+++ b/server/lib/deltacloud/drivers/google/google_driver.rb
@@ -21,9 +21,6 @@ module Deltacloud
 
 class GoogleDriver < Deltacloud::BaseDriver
 
-  def supported_collections; [:buckets]
-  end
-
   feature :buckets, :bucket_location
 
 #--
diff --git a/server/lib/deltacloud/drivers/mock/mock_client.rb b/server/lib/deltacloud/drivers/mock/mock_client.rb
index 94c56af..248cc49 100644
--- a/server/lib/deltacloud/drivers/mock/mock_client.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_client.rb
@@ -91,17 +91,6 @@ module Deltacloud::Drivers::Mock
       FileUtils.rm(fname) if File::exists?(fname)
     end
 
-    def store_cimi(collection, obj)
-      raise "Why no obj.name?" unless obj.name
-      File::open(cimi_file(collection, obj.name), "w") { |f| f.write(obj.to_json) }
-    end
-
-    def destroy_cimi(collection, id)
-      fname = cimi_file(collection, id)
-      raise "No such object: #{id} in #{collection} collection" unless File::exists?(fname)
-      FileUtils.rm(fname)
-    end
-
     def load_all_cimi(model_name)
         model_files = Dir[File::join(cimi_dir(model_name), "*.json")]
         model_files.map{|f| File.read(f)}
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb
index b58872c..15f06fb 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
@@ -14,28 +14,16 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-
 require 'yaml'
 require 'base64'
 require 'etc'
-require 'deltacloud/base_driver'
-require 'deltacloud/drivers/mock/mock_client'
-require 'deltacloud/drivers/mock/mock_driver_cimi_methods'
+require_relative 'mock_client'
+require_relative 'mock_driver_cimi_methods'
 
 module Deltacloud::Drivers::Mock
 
   class MockDriver < Deltacloud::BaseDriver
 
-    # If the provider is set to storage, pretend to be a storage-only
-    # driver
-    def supported_collections
-      if api_provider == 'storage'
-        [:buckets]
-      else
-        DEFAULT_COLLECTIONS + [:buckets, :keys]
-      end
-    end
-
     ( REALMS = [
       Realm.new({
         :id=>'us',
@@ -299,11 +287,6 @@ module Deltacloud::Drivers::Mock
       snapshots
     end
 
-    def destroy_storage_snapshot(credentials, opts={})
-      check_credentials(credentials)
-      @client.destroy(:storage_snapshots, opts[:id])
-    end
-
     def keys(credentials, opts={})
       check_credentials(credentials)
       result = @client.build_all(Key)
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
index 2dec66b..bebc45c 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb
@@ -32,49 +32,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def create_network(credentials, opts={})
-      check_credentials(credentials)
-      id = "#{opts[:env].send("networks_url")}/#{opts[:name]}"
-      net_hsh = { "id"=> id,
-                  "name" => opts[:name],
-                  "description" => opts[:description],
-                  "created" => Time.now,
-                  "state" => "STARTED",
-                  "access" => opts[:network_config].access,
-                  "bandwithLimit" => opts[:network_config].bandwidth_limit,
-                  "trafficPriority" => opts[:network_config].traffic_priority,
-                  "maxTrafficDelay" => opts[:network_config].max_traffic_delay,
-                  "maxTrafficLoss" =>opts[:network_config].max_traffic_loss,
-                  "maxTrafficJitter" =>opts[:network_config].max_traffic_jitter,
-                  "routingGroup"=> { "href" => opts[:routing_group].id },
-                  "operations" => [{"rel"=>"edit", "href"=> id},
-                                   {"rel"=>"delete", "href"=> id}]    }
-      network = CIMI::Model::Network.from_json(JSON.generate(net_hsh))
-
-      @client.store_cimi(:network, network)
-      network
-    end
-
-    def delete_network(credentials, id)
-      check_credentials(credentials)
-      @client.destroy_cimi(:network, id)
-    end
-
-    def start_network(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "Network", "STARTED")
-    end
-
-    def stop_network(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "Network", "STOPPED")
-    end
-
-    def suspend_network(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "Network", "SUSPENDED")
-    end
-
     def network_configurations(credentials, opts={})
       check_credentials(credentials)
       if opts[:id].nil?
@@ -130,43 +87,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def create_vsp(credentials, opts={})
-      check_credentials(credentials)
-      id = "#{opts[:env].send("vsps_url")}/#{opts[:name]}"
-      vsp_hash = { "id"    => id,
-                    "name"  => opts[:name],
-                    "description" => opts[:description],
-                    "state" => "STARTED",
-                    "created" => Time.now,
-                    "bandwidthReservation"=>opts[:vsp_config].bandwidth_reservation,
-                    "trafficPriority"=>opts[:vsp_config].traffic_priority,
-                    "maxTrafficDelay"=>opts[:vsp_config].max_traffic_delay,
-                    "maxTrafficLoss"=>opts[:vsp_config].max_traffic_loss,
-                    "maxTrafficJitter"=>opts[:vsp_config].max_traffic_jitter,
-                    "network" => {"href" => opts[:network].id},
-                    "operations" => [{"rel"=>"edit", "href"=> id},
-                                     {"rel"=>"delete", "href"=> id}]
-                   }
-      vsp = CIMI::Model::VSP.from_json(JSON.generate(vsp_hash))
-      @client.store_cimi(:vsp, vsp)
-      vsp
-    end
-
-    def start_vsp(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "VSP", "STARTED")
-    end
-
-    def stop_vsp(credentials, id)
-      check_credentials(credentials)
-      update_object_state(id, "VSP", "STOPPED")
-    end
-
-    def delete_vsp(credentials, id)
-      check_credentials(credentials)
-      @client.destroy_cimi(:vsp, id)
-    end
-
     def vsp_configurations(credentials, opts={})
       check_credentials(credentials)
       if opts[:id].nil?
@@ -189,56 +109,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def addresses(credentials, opts={})
-      check_credentials(credentials)
-      if opts[:id].nil?
-        addresses = @client.load_all_cimi(:address).map{|addr| CIMI::Model::Address.from_json(addr)}
-        addresses.map{|addr|convert_cimi_mock_urls(:address, addr, opts[:env])}.flatten
-      else
-        address = CIMI::Model::Address.from_json(@client.load_cimi(:address, opts[:id]))
-        convert_cimi_mock_urls(:address, address, opts[:env])
-      end
-    end
-
-    def create_address(credentials, opts={})
-      check_credentials(credentials)
-      id = "#{opts[:env].send("addresses_url")}/#{opts[:name]}"
-      addr_hash = { "id"    => id,
-                    "name"  => opts[:name],
-                    "description" => opts[:description],
-                    "created" => Time.now,
-                    "hostName" => opts[:address_template].hostname,
-                    "allocation" => opts[:address_template].allocation,
-                    "defaultGateway" => opts[:address_template].default_gateway,
-                    "dns" => opts[:address_template].dns,
-                    "macAddress" => opts[:address_template].mac_address,
-                    "protocol" => opts[:address_template].protocol,
-                    "mask" => opts[:address_template].mask,
-                    "network" => {"href" => opts[:address_template].network.href},
-                    "operations" => [{"rel"=>"edit", "href"=> id},
-                                     {"rel"=>"delete", "href"=> id}]
-                   }
-      address = CIMI::Model::Address.from_json(JSON.generate(addr_hash))
-      @client.store_cimi(:address, address)
-      address
-    end
-
-    def delete_address(credentials, id)
-      check_credentials(credentials)
-      @client.destroy_cimi(:address, id)
-    end
-
-    def address_templates(credentials, opts={})
-      check_credentials(credentials)
-      if opts[:id].nil?
-        address_templates = @client.load_all_cimi(:address_template).map{|addr_templ| CIMI::Model::AddressTemplate.from_json(addr_templ)}
-        address_templates.map{|addr_templ|convert_cimi_mock_urls(:address_template, addr_templ, opts[:env])}.flatten
-      else
-        address_template = CIMI::Model::AddressTemplate.from_json(@client.load_cimi(:address_template, opts[:id]))
-        convert_cimi_mock_urls(:address_template, address_template, opts[:env])
-      end
-    end
-
     private
 
     def convert_cimi_mock_urls(model_name, cimi_object, context)
@@ -270,15 +140,6 @@ module Deltacloud::Drivers::Mock
       end
     end
 
-    def update_object_state(id, object, new_state)
-      klass = CIMI::Model.const_get("#{object}")
-      symbol = object.to_s.downcase.singularize.intern
-      obj = klass.from_json(@client.load_cimi(symbol, id))
-      obj.state = new_state
-      @client.store_cimi(symbol, obj)
-      obj
-    end
-
   end
 
 end
diff --git a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
index 371e170..03c337f 100644
--- a/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
+++ b/server/lib/deltacloud/drivers/opennebula/opennebula_driver.rb
@@ -28,10 +28,6 @@ module Deltacloud
 
 class OpennebulaDriver < Deltacloud::BaseDriver
 
-  def supported_collections
-    DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
-  end
-
   ######################################################################
   # Hardware profiles
   #####################################################################
@@ -152,8 +148,8 @@ class OpennebulaDriver < Deltacloud::BaseDriver
     running.to(:running)        .on( :reboot )
     running.to(:stopping)       .on( :stop )
     stopping.to(:stopped)       .automatically
-    running.to(:stopping)       .on( :destroy )
-    stopping.to(:finish)        .automatically
+    running.to(:shutting_down)  .on( :destroy )
+    shutting_down.to(:finish)   .automatically
   end
 
   def instances(credentials, opts=nil)
diff --git a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
index c9ec95b..5d54d5b 100644
--- a/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
+++ b/server/lib/deltacloud/drivers/openstack/openstack_driver.rb
@@ -14,9 +14,9 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'openstack/compute'
 require 'tempfile'
+
 module Deltacloud
   module Drivers
     module Openstack
@@ -27,16 +27,12 @@ module Deltacloud
         feature :instances, :user_files
         feature :images, :user_name
 
-        def supported_collections
-          DEFAULT_COLLECTIONS - [ :storage_snapshots, :storage_volumes  ] #+ [ :buckets ]
-        end
-
         define_instance_states do
           start.to( :pending )          .on( :create )
           pending.to( :running )        .automatically
           running.to( :running )        .on( :reboot )
-          running.to( :stopping )       .on( :stop )
-          stopping.to( :stopped )       .automatically
+          running.to( :shutting_down )  .on( :stop )
+          shutting_down.to( :stopped )  .automatically
           stopped.to( :finish )         .automatically
         end
 
@@ -140,7 +136,7 @@ module Deltacloud
           params[:name] = (opts[:name] && opts[:name].length>0)? opts[:name] : Time.now.to_s
           params[:imageRef] = image_id
           params[:flavorRef] =  (opts[:hwp_id] && opts[:hwp_id].length>0) ?
-                          opts[:hwp_id] : hardware_profiles(credentials).first.name
+                          opts[:hwp_id] : hardware_profiles(credentials).first
           if opts[:password] && opts[:password].length > 0
             params[:adminPass]=opts[:password]
           end
diff --git a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
index 1b019d4..f59f832 100644
--- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
+++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
@@ -14,7 +14,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/base_driver'
 require 'cloudfiles'
 require 'cloudservers'
 require 'base64'
@@ -30,10 +29,6 @@ class RackspaceDriver < Deltacloud::BaseDriver
   feature :instances, :user_files
   feature :images, :user_name
 
-  def supported_collections
-    DEFAULT_COLLECTIONS + [ :buckets ] - [ :storage_snapshots, :storage_volumes ]
-  end
-
   def hardware_profiles(credentials, opts = {})
     rs = new_client( credentials )
     results = []
@@ -194,8 +189,8 @@ class RackspaceDriver < Deltacloud::BaseDriver
     start.to( :pending )          .on( :create )
     pending.to( :running )        .automatically
     running.to( :running )        .on( :reboot )
-    running.to( :stopping )       .on( :stop )
-    stopping.to( :stopped )       .automatically
+    running.to( :shutting_down )  .on( :stop )
+    shutting_down.to( :stopped )  .automatically
     stopped.to( :finish )         .automatically
   end
 
diff --git a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
index 1c96df7..f138f03 100644
--- a/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
+++ b/server/lib/deltacloud/drivers/rhevm/rhevm_driver.rb
@@ -14,27 +14,24 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/base_driver'
 require 'rbovirt'
 
 module Deltacloud
   module Drivers
-    module RHEVM
+    module Rhevm
 
-class RHEVMDriver < Deltacloud::BaseDriver
+class RhevmDriver < Deltacloud::BaseDriver
 
-  def supported_collections
-    DEFAULT_COLLECTIONS - [:storage_snapshots]
-  end
-
-  feature :instances, :user_name do
-    constraint :max_length, 50
+  Sinatra::Rabbit::InstancesCollection.features do
+    feature :user_name, :for => :instances do
+      constrain :max_length, 50
+    end
   end
 
   feature :instances, :user_data
   feature :images, :user_name
 
-  USER_NAME_MAX = feature(:instances, :user_name).constraints[:max_length]
+  USER_NAME_MAX = Sinatra::Rabbit::InstancesCollection.feature(:user_name).constraints[:max_length]
 
   # FIXME: These values are just for ilustration
   # Also I choosed 'SERVER' and 'DESKTOP' names
diff --git a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
index 58f8e1b..f44336a 100644
--- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
+++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb
@@ -41,17 +41,16 @@ class RimuHostingClient
       headers["Authorization"] = @auth
     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]]
+    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
+    if(res['response_type'] == "ERROR" and ( (res['error_info']['error_class'] == "PermissionException") or
 					     (res['error_info']['error_class'] == "LoginRequired") ))
-        raise "AuthFailure"
-      end
-      res
+      raise "AuthFailure"
     end
+    res
   end
 
   def list_images
@@ -82,6 +81,6 @@ class RimuHostingClient
   end
 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..8633d53 100644
--- a/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
+++ b/server/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb
@@ -16,7 +16,6 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require "deltacloud/base_driver"
 require "deltacloud/drivers/rimuhosting/rimuhosting_client"
 
 module Deltacloud
@@ -131,9 +130,9 @@ class RimuHostingDriver < Deltacloud::BaseDriver
             :owner_id => "root",
             :instance_profile => InstanceProfile.new("none"),
             :actions => instance_actions_for("RUNNING"),
-            :public_addresses => [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] ) ],
-            :launch_time => inst["billing_info"]["order_date"]["iso_format"]
-    })
+            :public_addresses => [ InstanceAddress.new(inst["allocated_ips"]["primary_ip"] )],
+            :launch_time => inst["billing_info"]["order_date"]["iso_format"]}
+                )
   end
 
   define_instance_states do
@@ -142,9 +141,9 @@ class RimuHostingDriver < Deltacloud::BaseDriver
     pending.to( :running )        .automatically
 
     running.to( :running )        .on(:reboot)
-    running.to( :stopping )       .on(:stop)
+    running.to( :shutting_down )  .on(:stop)
 
-    stopping.to( :stopped )       .automatically
+    shutting_down.to( :stopped )  .automatically
 
     stopped.to( :finish )         .automatically
   end
diff --git a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
index 2dba02a..2e087cb 100644
--- a/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
+++ b/server/lib/deltacloud/drivers/terremark/terremark_driver.rb
@@ -19,8 +19,7 @@
 # https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/d-complete-vcloud-express-api-document.aspx
 #
 # 02 May 2010
-#
-require 'deltacloud/base_driver'
+
 require 'fog'
 require 'excon'
 require 'nokogiri'
@@ -118,8 +117,8 @@ VAPP_STATE_MAP = { "0" =>  "PENDING", "1" =>  "PENDING", "2" =>  "STOPPED", "4"
     pending.to(:stopped)          .automatically
     stopped.to(:running)          .on( :start )
     running.to(:running)          .on( :reboot )
-    running.to(:stopping)         .on( :stop )
-    stopping.to(:stopped)         .automatically
+    running.to(:shutting_down)    .on( :stop )
+    shutting_down.to(:stopped)    .automatically
     stopped.to(:finish)           .on( :destroy )
    end
 
diff --git a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
index e16be2f..7ac908a 100644
--- a/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
+++ b/server/lib/deltacloud/drivers/vsphere/vsphere_driver.rb
@@ -14,18 +14,17 @@
 # under the License.
 #
 
-require 'deltacloud/base_driver'
 require 'rbvmomi'
 require 'deltacloud/drivers/vsphere/vsphere_client'
 
-module Deltacloud::Drivers::VSphere
+module Deltacloud::Drivers::Vsphere
 
   MAPPER_STORAGE_ROOT = File::join("/var/tmp", "deltacloud-vsphere-#{ENV["USER"]}")
 
-  class VSphereDriver < Deltacloud::BaseDriver
+  class VsphereDriver < Deltacloud::BaseDriver
 
     include Deltacloud::Drivers::VSphere::Helper
-    include Deltacloud::Drivers::VSphere::FileManager
+    include VSphere::FileManager
 
     # You can use 'user_iso' feature to set 'user_iso' parameter when creating
     # a new instance where this parameter can hold gzipped CDROM iso which will
@@ -34,10 +33,6 @@ module Deltacloud::Drivers::VSphere
     feature :instances, :user_data
     feature :instances, :user_name
 
-    def supported_collections
-      DEFAULT_COLLECTIONS - [:storage_volumes, :storage_snapshots]
-    end
-
     # There is just one hardware profile where memory is measured using maximum
     # memory available on ESX for virtual machines and CPU using maximum free
     # CPU cores in ESX.
@@ -68,8 +63,8 @@ module Deltacloud::Drivers::VSphere
       pending.to(:stopped)        .automatically
       stopped.to(:running)        .on( :start )
       running.to(:running)        .on( :reboot )
-      running.to(:stopping)       .on( :stop )
-      stopping.to(:stopped)       .automatically
+      running.to(:shutting_down)  .on( :stop )
+      shutting_down.to(:stopped)  .automatically
       stopped.to(:finish)         .on( :destroy )
     end
 
-- 
1.7.10


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

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


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

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


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

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


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

diff --git a/server/Rakefile b/server/Rakefile
index 8543285..2a765b7 100644
--- a/server/Rakefile
+++ b/server/Rakefile
@@ -193,3 +193,73 @@ namespace :mock do
 
   end
 end
+
+namespace :rabbit do
+  load File.join(File.dirname(__FILE__), 'config.ru')
+
+  desc "List the routes defined by Rabbit"
+  task :routes do
+    Deltacloud.collections.each do |c|
+      puts "\033[1;32;m#{c.name}\33[0m"
+      c.operations.each do |o|
+        puts "\033[1;37m%6s\033[0m :%-10s %-30s (%s)" % [
+          o.http_method.to_s.upcase,
+          o.operation_name,
+          o.full_path,
+          o.description[0..100]
+        ]
+      end
+      unless c.collections.empty?
+        puts
+        c.collections.each do |s|
+          puts "\033[1;32;m#{s.name}\33[0m"
+          s.operations.each do |o|
+            puts "\033[1;37m%6s\033[0m :%-10s %-30s (%s)" % [
+              o.http_method.to_s.upcase,
+              o.operation_name,
+              o.full_path,
+              o.description[0..100]
+            ]
+          end
+        end
+      end
+      puts
+    end
+  end
+
+  Deltacloud.collections.each do |c|
+    desc "Show details for #{c.collection_name} collection"
+    task :"#{c.collection_name}" do
+      puts "\033[1;32;m#{c.name} -> #{c.collection_name}\33[0m"
+      puts
+      puts c.description
+      puts
+      puts "Features:\n\n"
+      c.features.each do |f|
+        puts "\033[1;36;m:%-12s \33[0m%s\33[0m" % [
+          f.name,
+          f.description
+        ]
+      end
+      puts
+    end
+    c.operations.each do |o|
+      desc "Show details for #{o.operation_name} operation on #{c.collection_name} collection"
+      task :"#{c.collection_name}:#{o.operation_name}" do
+        puts "\033[1;32;m#{o.name} -> #{o.full_path}\33[0m"
+        puts
+        puts "Parameters:\n\n"
+        o.params.each do |p|
+          puts "\033[1;36;m:%-12s\33[1;33;m %-12s \33[0m%s\33[0m" % [
+            p.name,
+            p.klass.to_s.capitalize + (p.required? ? "\33[1;31m*\33[0m\t  " : ''),
+            p.description
+         ]
+        end
+        puts
+      end
+    end
+  end
+
+end
+
-- 
1.7.10


[PATCH core 08/32] Core: Fixed config.ru file to spawn a modular application

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/config.ru |   44 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/server/config.ru b/server/config.ru
index a1f9efd..f17de43 100644
--- a/server/config.ru
+++ b/server/config.ru
@@ -14,14 +14,46 @@
 # 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')
+# Set the API frontend use ('cimi' or 'deltacloud', default is 'deltacloud')
+ENV['API_FRONTEND'] ||= 'deltacloud'
 
-server_dir = ENV['API_FRONTEND'] == 'cimi' ? 'cimi' : 'deltacloud'
+# We need to set different API version and entrypoint location
+if ENV['API_FRONTEND'] == 'deltacloud'
+  API_VERSION = "9.9.9"
+  API_ROOT_URL = "/api"
+elsif ENV['API_FRONTEND'] == 'cimi'
+  API_VERSION = "1.0.0"
+  API_ROOT_URL = "/cloudEntryPoint"
+end
 
-load File.join($top_srcdir, 'lib', server_dir, 'server.rb')
+#begin
+  require File.join(File.dirname(__FILE__), 'lib', ENV['API_FRONTEND'], 'server.rb')
+#rescue LoadError => e
+#  puts "[ERROR] The specified frontend (#{ENV['API_FRONTEND']}) not supported (#{e.message})"
+#  exit 1
+#end
 
-run Sinatra::Application
+if self.respond_to? :map
+  map "/" do
+    class IndexEntrypoint < Sinatra::Base
+      get "/" do
+        redirect API_ROOT_URL, 301
+      end
+    end
+    run IndexEntrypoint
+  end
+
+  map API_ROOT_URL do
+    use Rack::Static, :urls => ["/stylesheets", "/javascripts"], :root => "public"
+    use Rack::Session::Cookie
+    case ENV['API_FRONTEND']
+      when 'deltacloud' then run Rack::Cascade.new([Deltacloud::API])
+      when 'cimi' then run Rack::Cascade.new([CIMI::API])
+    end
+  end
+end
-- 
1.7.10


[PATCH core 17/32] Core: Removed old core_ext and base_driver

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/base_driver.rb |   18 ------------------
 server/lib/deltacloud/core_ext.rb    |   21 ---------------------
 2 files changed, 39 deletions(-)
 delete mode 100644 server/lib/deltacloud/base_driver.rb
 delete mode 100644 server/lib/deltacloud/core_ext.rb

diff --git a/server/lib/deltacloud/base_driver.rb b/server/lib/deltacloud/base_driver.rb
deleted file mode 100644
index 77cdc84..0000000
--- a/server/lib/deltacloud/base_driver.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/base_driver/base_driver'
-require 'deltacloud/base_driver/features'
diff --git a/server/lib/deltacloud/core_ext.rb b/server/lib/deltacloud/core_ext.rb
deleted file mode 100644
index fedbc18..0000000
--- a/server/lib/deltacloud/core_ext.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/core_ext/string'
-require 'deltacloud/core_ext/integer'
-require 'deltacloud/core_ext/hash'
-require 'deltacloud/core_ext/array'
-require 'deltacloud/core_ext/proc'
-- 
1.7.10


[PATCH core 29/32] Core: Respond with application/xml when no media type is negotiated

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


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

diff --git a/server/lib/sinatra/rack_accept.rb b/server/lib/sinatra/rack_accept.rb
index e4a0f1f..2064440 100644
--- a/server/lib/sinatra/rack_accept.rb
+++ b/server/lib/sinatra/rack_accept.rb
@@ -81,7 +81,11 @@ module Rack
           end.first
           if @media_type and @media_type[0]
             @media_type = @media_type[0]
-            headers 'Content-Type' => Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type][:return]
+            if  Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type]
+              headers 'Content-Type' => Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type][:return]
+            else
+              headers 'Content-Type' => 'application/xml'
+            end
             wants[@media_type.to_sym].call if wants[@media_type.to_sym]
           else
             headers 'Content-Type' => nil
-- 
1.7.10


Re: [PATCH core 03/32] Core: Added wrapper for autoloading collections

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/10/12, David Lutterkort wrote:
> On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> > From: Michal Fojtik <mf...@redhat.com>
> 
> [ I am looking at your branch, but it's more convenient to reply to
> individual patches ]
> 
> This and 2/32 seem like a little too much magic to me; why do this
> rather than have a big server.rb ? It's 1200 lines right now, but they
> are fairly boring code, and I like being able to see all that code at
> once.

Hi,

Sure not a big deal. I can remove the 'use' in loop and add all collections
to the Deltacloud::API class by hand. I agree that this will make the code more
readable and make the user see what collections are supported by API.

I'll send a patch to do it today.

  -- Michal

> 
> David
> 
> 

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

Re: [PATCH core 03/32] Core: Added wrapper for autoloading collections

Posted by David Lutterkort <lu...@redhat.com>.
On Thu, 2012-05-10 at 10:25 +0200, Michal Fojtik wrote:
> On 05/10/12, David Lutterkort wrote:
> > On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> > > From: Michal Fojtik <mf...@redhat.com>
> > 
> > [ I am looking at your branch, but it's more convenient to reply to
> > individual patches ]
> > 
> > This and 2/32 seem like a little too much magic to me; why do this
> > rather than have a big server.rb ? It's 1200 lines right now, but they
> > are fairly boring code, and I like being able to see all that code at
> > once.
> 
> Sorry, I was too fast with replying ;-) You are referring to the collection
> subfolder not to lazy-loading.
> 
> My thoughts was to make it more readable and structured when it will be
> splitted into separate files.

After looking at it again, I am fine with splitting it across multiple
files; I mostly object to the lazy-loading stuff. IMHO, it makes the
code less readable: when I open collection.rb, I expect to see a bunch
of 'require' statements and not much else; instead I need to actually
read through the code now and figure out that it essentially does what
the require's would do.

And having explicit 'use' in server.rb would make things more readable,
too.

David



Re: [PATCH core 03/32] Core: Added wrapper for autoloading collections

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/10/12, David Lutterkort wrote:
> On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> > From: Michal Fojtik <mf...@redhat.com>
> 
> [ I am looking at your branch, but it's more convenient to reply to
> individual patches ]
> 
> This and 2/32 seem like a little too much magic to me; why do this
> rather than have a big server.rb ? It's 1200 lines right now, but they
> are fairly boring code, and I like being able to see all that code at
> once.

Sorry, I was too fast with replying ;-) You are referring to the collection
subfolder not to lazy-loading.

My thoughts was to make it more readable and structured when it will be
splitted into separate files.

Having everything in one place is nice but when you first look into the
server.rb it honestly looks like a mess :-)

IMHO having the collections in separate files will make it more easy to fix
things in particular collection, without making people rebasing and fixing
conflicts in one big server.rb.

Also since this code use Base class from Sinatra, all collections are just
'modules' that can be plugged and un-plugged as needed. So you can for
example use DC as base for your application where you choose just
collections you really want to use.

Another thing is that I guess in future we will need to add more
collections, like for managing networks/etc so the amount of code in
server.rb will eventually grow. I think that for the people that want to
add new collection to Deltacloud, it's now more easy just 'copy' the
collection file, rename it and add their stuff there.

  -- Michal

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

Re: [PATCH core 03/32] Core: Added wrapper for autoloading collections

Posted by David Lutterkort <lu...@redhat.com>.
On Tue, 2012-04-17 at 15:39 +0200, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>

[ I am looking at your branch, but it's more convenient to reply to
individual patches ]

This and 2/32 seem like a little too much magic to me; why do this
rather than have a big server.rb ? It's 1200 lines right now, but they
are fairly boring code, and I like being able to see all that code at
once.

David



[PATCH core 03/32] Core: Added wrapper for autoloading collections

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


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

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


[PATCH core 10/32] Core: Added hardware_profile model and moved instance_states to models

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/models/hardware_profile.rb |  194 ++++++++++++++++++++++
 server/lib/deltacloud/models/state_machine.rb    |   99 +++++++++++
 server/lib/deltacloud/state_machine.rb           |  115 -------------
 3 files changed, 293 insertions(+), 115 deletions(-)
 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/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


[PATCH core 28/32] Core: Added deltacloud library wrapper (require 'lib/deltacloud')

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


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

diff --git a/server/lib/deltacloud.rb b/server/lib/deltacloud.rb
index 6ff547e..d64797d 100644
--- a/server/lib/deltacloud.rb
+++ b/server/lib/deltacloud.rb
@@ -1,4 +1,3 @@
-#
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.  The
@@ -14,14 +13,59 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'deltacloud/drivers'
+require 'rubygems'
+
+unless Kernel.respond_to?(:require_relative)
+  module Kernel
+    def require_relative(path)
+      require File.join(File.dirname(caller[0]), path.to_str)
+    end
+  end
+end
+
+require 'ostruct'
+
+require_relative 'deltacloud/core_ext/string'
+require_relative 'deltacloud/core_ext/array'
+require_relative 'deltacloud/core_ext/hash'
+require_relative 'deltacloud/core_ext/integer'
+require_relative 'deltacloud/core_ext/proc'
+require_relative 'deltacloud/models'
+require_relative 'deltacloud/drivers'
+require_relative 'deltacloud/helpers/driver_helper'
+
+module Deltacloud
+
+  def self.drivers
+    Drivers.driver_config
+  end
+
+  class Library
+    include Helpers::Drivers
+    attr_reader :backend, :credentials
+
+    def initialize(driver_name, opts={}, &block)
+      Thread.current[:driver] = driver_name.to_s
+      Thread.current[:provider] = opts[:provider] if opts[:provider]
+      @backend = driver
+      @credentials = OpenStruct.new(:user => opts[:user], :password => opts[:password])
+      yield self if block_given?
+    end
+
+    def method_missing(name, *args)
+      return super unless backend.respond_to? name
+      begin
+        params = ([@credentials] + args).flatten
+        backend.send(name, *params)
+      rescue ArgumentError
+        backend.send(name, *args)
+      end
+    end
+
+  end
 
-require 'deltacloud/core_ext'
+  def self.new(driver_name, opts={}, &block)
+    Library.new(driver_name, opts, &block)
+  end
 
-require 'deltacloud/base_driver'
-require 'deltacloud/hardware_profile'
-require 'deltacloud/state_machine'
-require 'deltacloud/helpers'
-require 'deltacloud/models'
-require 'deltacloud/validation'
-require 'deltacloud/runner'
+end
-- 
1.7.10


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

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

Just a quick note. Seems like the dragons blow up my github
'deltacloud_modular' branch and I cannot rebase against master anymore.
GIT is trying to apply all patches twice, which lead to infinite fun with
resolving conflicts.

I created a new branch called 'modular' on github[1]. Please switch to
using this branch. Sorry for this :-)


  -- Michal


> m/ruby/1.8/gems/cucumber-1.1.4/bin/../lib/cucumber/formatter/io.rb:7:in `initialize'
> >
> 
> The Cucumber tests should be launched from the 'server' directory:
> 
> firefly ~/code/core/server $ rake cucumber:mock:test
> ...........
> 41 scenarios (41 passed)
> 292 steps (292 passed)
> 0m10.489s
> 
> Note that I just fixed the Mock Cucumber suite, still working on EC2 one,
> but I assume since there were no changes to EC2 driver they will just work.
> 
> > To commit these, we need to get to a state where all the tests pass;
> > that's the biggest blocker right now.
> 
> Agree, I'll do that as high priority. Btw. I suggest to replace the 'mock'
> unit tests we have in server/tests/drivers/mock with the 'api' tests. They
> are doing the same thing now and the 'api' tests are more up-to-date.
> What do you think?
> 
> > Also, to make the patch series a little less daunting, you might
> > consider splitting patches that aren't directly related to modularizing
> > DC out (e.g., 14/32 or 30-32/32) This will make it much easier to review
> > them and get them committed separately.
> 
> Yeah, should I do that and send a new patch bomb? I can do it when rebasing
> against master when pushing but that will not be anyhow usefull for review
> ;-)
> 
> 
>   -- michal
> 
> -- 
> Michal Fojtik
> Sr. Software Engineer, Deltacloud API (http://deltacloud.org)

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

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

Posted by David Lutterkort <lu...@redhat.com>.
Hi Michal,

On Fri, 2012-05-11 at 12:56 +0200, Michal Fojtik wrote:
> On 05/10/12, David Lutterkort wrote:
> > I get some errors on the modular branch; they need to be addressed
> > before we can commit this patch series.
> > 
> > (1) Running 'rake test' gives me
> >         
> >         /homes/lutter/.gem/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/module.rb:36:in `const_missing': uninitialized constant Deltacloud::Helpers::Application::API_ROOT_URL (NameError)
> 
> Right, this task will trigger the Test::Unit tests we have. I can fix them
> to use Deltacloud::API.

Yes, either that or get rid of them entirely.

> > (5) Running 'rake features' in tests/ gives me 
> > 
> >         Error creating formatter: html (Errno::ENOENT)
> >         /homes/lutter/.gem/ruby/1.8/gems/cucumber-1.1.4/bin/../lib/cucumber/formatter/io.rb:7:in `initialize'
> >
> 
> The Cucumber tests should be launched from the 'server' directory:
> 
> firefly ~/code/core/server $ rake cucumber:mock:test
> ...........
> 41 scenarios (41 passed)
> 292 steps (292 passed)
> 0m10.489s
> 
> Note that I just fixed the Mock Cucumber suite, still working on EC2 one,
> but I assume since there were no changes to EC2 driver they will just work.

The mock cucumber tests now work for me too, on your new branch. Longer
term, we need to have a good look at how these are set up right now -
ideally tests/ would have its own Rakefile that can be pointed at
arbitrary drivers.

> > To commit these, we need to get to a state where all the tests pass;
> > that's the biggest blocker right now.
> 
> Agree, I'll do that as high priority. Btw. I suggest to replace the 'mock'
> unit tests we have in server/tests/drivers/mock with the 'api' tests. They
> are doing the same thing now and the 'api' tests are more up-to-date.
> What do you think?

If they are just duplication, then yes, we should get rid of them.

> > Also, to make the patch series a little less daunting, you might
> > consider splitting patches that aren't directly related to modularizing
> > DC out (e.g., 14/32 or 30-32/32) This will make it much easier to review
> > them and get them committed separately.
> 
> Yeah, should I do that and send a new patch bomb? I can do it when rebasing
> against master when pushing but that will not be anyhow usefull for review
> ;-)

I mostly meant that to speed things up: send those unrelated patches
separately while you're still working on the modular stuff; that way,
there's less churn when the modular patches go in. And it's easier to
review a few patch series with a handful of patches, rather than 40+
patches ;)

David


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

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/10/12, David Lutterkort wrote:
> I get some errors on the modular branch; they need to be addressed
> before we can commit this patch series.
> 
> (1) Running 'rake test' gives me
>         
>         /homes/lutter/.gem/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/module.rb:36:in `const_missing': uninitialized constant Deltacloud::Helpers::Application::API_ROOT_URL (NameError)

Right, this task will trigger the Test::Unit tests we have. I can fix them
to use Deltacloud::API.

> (2) Trying to upload a blob through the HTML UI gives me
> 
>         /homes/lutter/code/deltacloud/git/server/lib/deltacloud/./helpers/blob_stream_helper.rb:191:in `is_put_blob': undefined local variable or method `settings' for BlobStreamIO:Class (NameError)

Fixed in 638886b3cd87a09e4b0ea244e4b6c0dd94463c25

>         
> (3) minitest isn't mentioned in the Gemfile

Fixed in 314bba781b60e86f428ce30324e7b9d774954bf0

> 
> (4) running 'rake test:api' gives me
> 
>         test_0007_must_have_some_key_elements_inside_keys_(Deltacloud API Keys) [/homes/lutter/code/deltacloud/git/server/tests/drivers/api/keys_test.rb:43]:
>         Expected [] to not be empty.

Fixed in 3e2e3d9857c668d3c466bfec69a50b53d12da08d

> 
> (5) Running 'rake features' in tests/ gives me 
> 
>         Error creating formatter: html (Errno::ENOENT)
>         /homes/lutter/.gem/ruby/1.8/gems/cucumber-1.1.4/bin/../lib/cucumber/formatter/io.rb:7:in `initialize'
>

The Cucumber tests should be launched from the 'server' directory:

firefly ~/code/core/server $ rake cucumber:mock:test
...........
41 scenarios (41 passed)
292 steps (292 passed)
0m10.489s

Note that I just fixed the Mock Cucumber suite, still working on EC2 one,
but I assume since there were no changes to EC2 driver they will just work.

> To commit these, we need to get to a state where all the tests pass;
> that's the biggest blocker right now.

Agree, I'll do that as high priority. Btw. I suggest to replace the 'mock'
unit tests we have in server/tests/drivers/mock with the 'api' tests. They
are doing the same thing now and the 'api' tests are more up-to-date.
What do you think?

> Also, to make the patch series a little less daunting, you might
> consider splitting patches that aren't directly related to modularizing
> DC out (e.g., 14/32 or 30-32/32) This will make it much easier to review
> them and get them committed separately.

Yeah, should I do that and send a new patch bomb? I can do it when rebasing
against master when pushing but that will not be anyhow usefull for review
;-)


  -- michal

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

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

Posted by David Lutterkort <lu...@redhat.com>.
I get some errors on the modular branch; they need to be addressed
before we can commit this patch series.

(1) Running 'rake test' gives me
        
        /homes/lutter/.gem/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/module.rb:36:in `const_missing': uninitialized constant Deltacloud::Helpers::Application::API_ROOT_URL (NameError)
        
(2) Trying to upload a blob through the HTML UI gives me

        /homes/lutter/code/deltacloud/git/server/lib/deltacloud/./helpers/blob_stream_helper.rb:191:in `is_put_blob': undefined local variable or method `settings' for BlobStreamIO:Class (NameError)
        
(3) minitest isn't mentioned in the Gemfile

(4) running 'rake test:api' gives me

        test_0007_must_have_some_key_elements_inside_keys_(Deltacloud API Keys) [/homes/lutter/code/deltacloud/git/server/tests/drivers/api/keys_test.rb:43]:
        Expected [] to not be empty.

(5) Running 'rake features' in tests/ gives me 

        Error creating formatter: html (Errno::ENOENT)
        /homes/lutter/.gem/ruby/1.8/gems/cucumber-1.1.4/bin/../lib/cucumber/formatter/io.rb:7:in `initialize'
        

To commit these, we need to get to a state where all the tests pass;
that's the biggest blocker right now.

Also, to make the patch series a little less daunting, you might
consider splitting patches that aren't directly related to modularizing
DC out (e.g., 14/32 or 30-32/32) This will make it much easier to review
them and get them committed separately.

David



[PATCH core 31/32] Core: Replace driver_has_auth_features with more descriptive helper

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


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

diff --git a/server/views/instances/show.xml.haml b/server/views/instances/show.xml.haml
index b2fd5bf..3a62ed3 100644
--- a/server/views/instances/show.xml.haml
+++ b/server/views/instances/show.xml.haml
@@ -45,7 +45,7 @@
     %storage_volumes<
       - @instance.storage_volumes.each do |volume|
         %storage_volume{:href=> storage_volume_url(volume.keys.first), :id => volume.keys.first, :device => volume.values.first}
-  - if driver_has_auth_features?
+  - if driver.class.has_feature?(:authentication_key) or driver.class.has_feature?(:authentication_password)
     %authentication{ :type => driver_auth_feature_name }
       - if @instance.authn_feature_failed?
         %error  #{@instance.authn_error}
-- 
1.7.10


[PATCH core 25/32] CIMI: Moved the CIMI models from 'model' directory to 'models'

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/model/action.rb                    |   24 --
 server/lib/cimi/model/address.rb                   |   72 -----
 server/lib/cimi/model/address_collection.rb        |   34 ---
 server/lib/cimi/model/address_template.rb          |   54 ----
 .../lib/cimi/model/address_template_collection.rb  |   34 ---
 server/lib/cimi/model/base.rb                      |  249 ------------------
 server/lib/cimi/model/cloud_entry_point.rb         |   48 ----
 server/lib/cimi/model/entity_metadata.rb           |   83 ------
 .../lib/cimi/model/entity_metadata_collection.rb   |   31 ---
 server/lib/cimi/model/errors.rb                    |   48 ----
 server/lib/cimi/model/machine.rb                   |  229 ----------------
 server/lib/cimi/model/machine_admin.rb             |   59 -----
 server/lib/cimi/model/machine_admin_collection.rb  |   34 ---
 server/lib/cimi/model/machine_collection.rb        |   34 ---
 server/lib/cimi/model/machine_configuration.rb     |   70 -----
 .../cimi/model/machine_configuration_collection.rb |   34 ---
 server/lib/cimi/model/machine_image.rb             |   46 ----
 server/lib/cimi/model/machine_image_collection.rb  |   34 ---
 server/lib/cimi/model/machine_template.rb          |   41 ---
 .../lib/cimi/model/machine_template_collection.rb  |   34 ---
 server/lib/cimi/model/network.rb                   |  106 --------
 server/lib/cimi/model/network_collection.rb        |   34 ---
 server/lib/cimi/model/network_configuration.rb     |   49 ----
 .../cimi/model/network_configuration_collection.rb |   34 ---
 server/lib/cimi/model/network_template.rb          |   36 ---
 .../lib/cimi/model/network_template_collection.rb  |   35 ---
 server/lib/cimi/model/routing_group.rb             |   34 ---
 server/lib/cimi/model/routing_group_collection.rb  |   34 ---
 server/lib/cimi/model/routing_group_template.rb    |   34 ---
 .../model/routing_group_template_collection.rb     |   35 ---
 server/lib/cimi/model/schema.rb                    |  277 --------------------
 server/lib/cimi/model/volume.rb                    |  103 --------
 server/lib/cimi/model/volume_collection.rb         |   34 ---
 server/lib/cimi/model/volume_configuration.rb      |   60 -----
 .../cimi/model/volume_configuration_collection.rb  |   34 ---
 server/lib/cimi/model/volume_image.rb              |   49 ----
 server/lib/cimi/model/volume_image_collection.rb   |   34 ---
 server/lib/cimi/model/volume_template.rb           |   23 --
 .../lib/cimi/model/volume_template_collection.rb   |   34 ---
 server/lib/cimi/model/vsp.rb                       |  102 -------
 server/lib/cimi/model/vsp_collection.rb            |   34 ---
 server/lib/cimi/model/vsp_configuration.rb         |   40 ---
 .../lib/cimi/model/vsp_configuration_collection.rb |   34 ---
 server/lib/cimi/model/vsp_template.rb              |   34 ---
 server/lib/cimi/model/vsp_template_collection.rb   |   34 ---
 server/lib/cimi/models/action.rb                   |   24 ++
 server/lib/cimi/models/address.rb                  |   72 +++++
 server/lib/cimi/models/address_collection.rb       |   34 +++
 server/lib/cimi/models/address_template.rb         |   54 ++++
 .../lib/cimi/models/address_template_collection.rb |   34 +++
 server/lib/cimi/models/base.rb                     |  249 ++++++++++++++++++
 server/lib/cimi/models/cloud_entry_point.rb        |   46 ++++
 server/lib/cimi/models/entity_metadata.rb          |   84 ++++++
 .../lib/cimi/models/entity_metadata_collection.rb  |   31 +++
 server/lib/cimi/models/errors.rb                   |   48 ++++
 server/lib/cimi/models/machine.rb                  |  227 ++++++++++++++++
 server/lib/cimi/models/machine_admin.rb            |   59 +++++
 server/lib/cimi/models/machine_admin_collection.rb |   34 +++
 server/lib/cimi/models/machine_collection.rb       |   34 +++
 server/lib/cimi/models/machine_configuration.rb    |   70 +++++
 .../models/machine_configuration_collection.rb     |   34 +++
 server/lib/cimi/models/machine_image.rb            |   46 ++++
 server/lib/cimi/models/machine_image_collection.rb |   34 +++
 server/lib/cimi/models/machine_template.rb         |   41 +++
 .../lib/cimi/models/machine_template_collection.rb |   34 +++
 server/lib/cimi/models/network.rb                  |  109 ++++++++
 server/lib/cimi/models/network_collection.rb       |   34 +++
 server/lib/cimi/models/network_configuration.rb    |   49 ++++
 .../models/network_configuration_collection.rb     |   34 +++
 server/lib/cimi/models/network_template.rb         |   36 +++
 .../lib/cimi/models/network_template_collection.rb |   35 +++
 server/lib/cimi/models/routing_group.rb            |   34 +++
 server/lib/cimi/models/routing_group_collection.rb |   34 +++
 server/lib/cimi/models/routing_group_template.rb   |   34 +++
 .../models/routing_group_template_collection.rb    |   35 +++
 server/lib/cimi/models/schema.rb                   |  277 ++++++++++++++++++++
 server/lib/cimi/models/volume.rb                   |  103 ++++++++
 server/lib/cimi/models/volume_collection.rb        |   34 +++
 server/lib/cimi/models/volume_configuration.rb     |   60 +++++
 .../cimi/models/volume_configuration_collection.rb |   34 +++
 server/lib/cimi/models/volume_image.rb             |   49 ++++
 server/lib/cimi/models/volume_image_collection.rb  |   34 +++
 server/lib/cimi/models/volume_template.rb          |   23 ++
 .../lib/cimi/models/volume_template_collection.rb  |   34 +++
 server/lib/cimi/models/vsp.rb                      |  102 +++++++
 server/lib/cimi/models/vsp_collection.rb           |   34 +++
 server/lib/cimi/models/vsp_configuration.rb        |   40 +++
 .../cimi/models/vsp_configuration_collection.rb    |   34 +++
 server/lib/cimi/models/vsp_template.rb             |   34 +++
 server/lib/cimi/models/vsp_template_collection.rb  |   34 +++
 90 files changed, 2649 insertions(+), 2649 deletions(-)
 delete mode 100644 server/lib/cimi/model/action.rb
 delete mode 100644 server/lib/cimi/model/address.rb
 delete mode 100644 server/lib/cimi/model/address_collection.rb
 delete mode 100644 server/lib/cimi/model/address_template.rb
 delete mode 100644 server/lib/cimi/model/address_template_collection.rb
 delete mode 100644 server/lib/cimi/model/base.rb
 delete mode 100644 server/lib/cimi/model/cloud_entry_point.rb
 delete mode 100644 server/lib/cimi/model/entity_metadata.rb
 delete mode 100644 server/lib/cimi/model/entity_metadata_collection.rb
 delete mode 100644 server/lib/cimi/model/errors.rb
 delete mode 100644 server/lib/cimi/model/machine.rb
 delete mode 100644 server/lib/cimi/model/machine_admin.rb
 delete mode 100644 server/lib/cimi/model/machine_admin_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_configuration.rb
 delete mode 100644 server/lib/cimi/model/machine_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_image.rb
 delete mode 100644 server/lib/cimi/model/machine_image_collection.rb
 delete mode 100644 server/lib/cimi/model/machine_template.rb
 delete mode 100644 server/lib/cimi/model/machine_template_collection.rb
 delete mode 100644 server/lib/cimi/model/network.rb
 delete mode 100644 server/lib/cimi/model/network_collection.rb
 delete mode 100644 server/lib/cimi/model/network_configuration.rb
 delete mode 100644 server/lib/cimi/model/network_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/network_template.rb
 delete mode 100644 server/lib/cimi/model/network_template_collection.rb
 delete mode 100644 server/lib/cimi/model/routing_group.rb
 delete mode 100644 server/lib/cimi/model/routing_group_collection.rb
 delete mode 100644 server/lib/cimi/model/routing_group_template.rb
 delete mode 100644 server/lib/cimi/model/routing_group_template_collection.rb
 delete mode 100644 server/lib/cimi/model/schema.rb
 delete mode 100644 server/lib/cimi/model/volume.rb
 delete mode 100644 server/lib/cimi/model/volume_collection.rb
 delete mode 100644 server/lib/cimi/model/volume_configuration.rb
 delete mode 100644 server/lib/cimi/model/volume_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/volume_image.rb
 delete mode 100644 server/lib/cimi/model/volume_image_collection.rb
 delete mode 100644 server/lib/cimi/model/volume_template.rb
 delete mode 100644 server/lib/cimi/model/volume_template_collection.rb
 delete mode 100644 server/lib/cimi/model/vsp.rb
 delete mode 100644 server/lib/cimi/model/vsp_collection.rb
 delete mode 100644 server/lib/cimi/model/vsp_configuration.rb
 delete mode 100644 server/lib/cimi/model/vsp_configuration_collection.rb
 delete mode 100644 server/lib/cimi/model/vsp_template.rb
 delete mode 100644 server/lib/cimi/model/vsp_template_collection.rb
 create mode 100644 server/lib/cimi/models/action.rb
 create mode 100644 server/lib/cimi/models/address.rb
 create mode 100644 server/lib/cimi/models/address_collection.rb
 create mode 100644 server/lib/cimi/models/address_template.rb
 create mode 100644 server/lib/cimi/models/address_template_collection.rb
 create mode 100644 server/lib/cimi/models/base.rb
 create mode 100644 server/lib/cimi/models/cloud_entry_point.rb
 create mode 100644 server/lib/cimi/models/entity_metadata.rb
 create mode 100644 server/lib/cimi/models/entity_metadata_collection.rb
 create mode 100644 server/lib/cimi/models/errors.rb
 create mode 100644 server/lib/cimi/models/machine.rb
 create mode 100644 server/lib/cimi/models/machine_admin.rb
 create mode 100644 server/lib/cimi/models/machine_admin_collection.rb
 create mode 100644 server/lib/cimi/models/machine_collection.rb
 create mode 100644 server/lib/cimi/models/machine_configuration.rb
 create mode 100644 server/lib/cimi/models/machine_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/machine_image.rb
 create mode 100644 server/lib/cimi/models/machine_image_collection.rb
 create mode 100644 server/lib/cimi/models/machine_template.rb
 create mode 100644 server/lib/cimi/models/machine_template_collection.rb
 create mode 100644 server/lib/cimi/models/network.rb
 create mode 100644 server/lib/cimi/models/network_collection.rb
 create mode 100644 server/lib/cimi/models/network_configuration.rb
 create mode 100644 server/lib/cimi/models/network_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/network_template.rb
 create mode 100644 server/lib/cimi/models/network_template_collection.rb
 create mode 100644 server/lib/cimi/models/routing_group.rb
 create mode 100644 server/lib/cimi/models/routing_group_collection.rb
 create mode 100644 server/lib/cimi/models/routing_group_template.rb
 create mode 100644 server/lib/cimi/models/routing_group_template_collection.rb
 create mode 100644 server/lib/cimi/models/schema.rb
 create mode 100644 server/lib/cimi/models/volume.rb
 create mode 100644 server/lib/cimi/models/volume_collection.rb
 create mode 100644 server/lib/cimi/models/volume_configuration.rb
 create mode 100644 server/lib/cimi/models/volume_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/volume_image.rb
 create mode 100644 server/lib/cimi/models/volume_image_collection.rb
 create mode 100644 server/lib/cimi/models/volume_template.rb
 create mode 100644 server/lib/cimi/models/volume_template_collection.rb
 create mode 100644 server/lib/cimi/models/vsp.rb
 create mode 100644 server/lib/cimi/models/vsp_collection.rb
 create mode 100644 server/lib/cimi/models/vsp_configuration.rb
 create mode 100644 server/lib/cimi/models/vsp_configuration_collection.rb
 create mode 100644 server/lib/cimi/models/vsp_template.rb
 create mode 100644 server/lib/cimi/models/vsp_template_collection.rb

diff --git a/server/lib/cimi/model/action.rb b/server/lib/cimi/model/action.rb
deleted file mode 100644
index c1c9908..0000000
--- a/server/lib/cimi/model/action.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Action < CIMI::Model::Base
-
-  text :action
-
-  def name
-    action.split('/').last.strip.intern
-  end
-
-end
diff --git a/server/lib/cimi/model/address.rb b/server/lib/cimi/model/address.rb
deleted file mode 100644
index 8838331..0000000
--- a/server/lib/cimi/model/address.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Address < CIMI::Model::Base
-
-  text :ip
-
-  text :hostname
-
-  text :allocation
-
-  text :default_gateway
-
-  text :dns
-
-  text :mac_address
-
-  text :protocol
-
-  text :mask
-
-  href :network
-
-  href :resource
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.addresses(context.credentials, {:env=>context})
-    else
-      context.driver.addresses(context.credentials, {:id=>id, :env=>context})
-    end
-  end
-
-  def self.create(request_body, context, type)
-    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
-    if input["addressTemplate"]["href"] #by reference
-      address_template = AddressTemplate.find(context.href_id(input["addressTemplate"]["href"], :address_templates), context)
-    else
-      case type
-        when :json
-          address_template = AddressTemplate.from_json(JSON.generate(input["addressTemplate"]))
-        when :xml
-          xml = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
-          address_template = AddressTemplate.from_xml(XmlSimple.xml_out(xml["addressTemplate"][0]))
-      end
-    end
-    params = {:name=>input["name"], :description=>input["description"], :address_template=>address_template, :env=>context }
-    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
-    context.driver.create_address(context.credentials, params)
-  end
-
-  def self.delete!(id, context)
-    context.driver.delete_address(context.credentials, id)
-  end
-
-end
diff --git a/server/lib/cimi/model/address_collection.rb b/server/lib/cimi/model/address_collection.rb
deleted file mode 100644
index eef6c51..0000000
--- a/server/lib/cimi/model/address_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::AddressCollection < CIMI::Model::Base
-
-  act_as_root_entity :address
-
-  array :addresses do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.addresses_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} AddressCollection",
-      :addresses => CIMI::Model::Address.all(context).map { |addr| { :href => addr.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/address_template.rb b/server/lib/cimi/model/address_template.rb
deleted file mode 100644
index 9d2c409..0000000
--- a/server/lib/cimi/model/address_template.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::AddressTemplate < CIMI::Model::Base
-
-  text :ip
-
-  text :hostname
-
-  text :allocation
-
-  text :default_gateway
-
-  text :dns
-
-  text :mac_address
-
-  text :protocol
-
-  text :mask
-
-  href :network
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.address_templates(context.credentials, {:env=>context})
-    else
-      context.driver.address_templates(context.credentials, {:id=>id, :env=>context})
-    end
-  end
-
-  def self.create(request_body, context, type)
-  end
-
-  def self.delete!(id, context)
-  end
-
-end
diff --git a/server/lib/cimi/model/address_template_collection.rb b/server/lib/cimi/model/address_template_collection.rb
deleted file mode 100644
index e973252..0000000
--- a/server/lib/cimi/model/address_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::AddressTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :address_template
-
-  array :address_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.address_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} AddressTemplateCollection",
-      :address_templates => AddressTemplate.all(context).map { |addr| { :href => addr.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/base.rb b/server/lib/cimi/model/base.rb
deleted file mode 100644
index 16812ac..0000000
--- a/server/lib/cimi/model/base.rb
+++ /dev/null
@@ -1,249 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'xmlsimple'
-require 'json'
-
-# The base class for any CIMI object that we either read from a request or
-# write as a response. This class handles serializing/deserializing XML and
-# JSON into a common form.
-#
-# == Defining the schema
-#
-# The conversion of XML and JSON into internal objects is based on a schema
-# that is defined through a DSL:
-#
-#   class Machine < CIMI::Model::Base
-#     text :status
-#     href :meter
-#     array :volumes do
-#       scalar :href, :attachment_point, :protocol
-#     end
-#   end
-#
-# The DSL automatically takes care of converting identifiers from their
-# underscored form to the camel-cased form used by CIMI. The above class
-# can be used in the following way:
-#
-#   machine = Machine.from_xml(some_xml)
-#   if machine.status == "UP"
-#     ...
-#   end
-#   sda = machine.volumes.find { |v| v.attachment_point == "/dev/sda" }
-#   handle_meter(machine.meter.href)
-#
-# The keywords for the DSL are
-#   [scalar(names, ...)]
-#     Define a scalar attribute; in JSON, this is represented as a string
-#     property. In XML, this can be represented in a number of ways,
-#     depending on whether the option :text is set:
-#       * :text not set: attribute on the enclosing element
-#       * :text == :direct: the text content of the enclosing element
-#       * :text == :nested: the text content of an element +<name>...</name>+
-#   [text(names)]
-#     A shorthand for +scalar(names, :text => :nested)+, i.e., for
-#     attributes that in XML are represented by their own tags
-#   [href(name)]
-#     A shorthand for +struct name { scalar :href }+; in JSON, this is
-#     represented as +{ name: { "href": string } }+, and in XML as +<name
-#     href="..."/>+
-#   [struct(name, opts, &block)]
-#     A structured subobject; the block defines the schema of the
-#     subobject. The +:content+ option can be used to specify the attribute
-#     that should receive the content of hte corresponding XML element
-#   [array(name, opts, &block)]
-#     An array of structured subobjects; the block defines the schema of
-#     the subobjects.
-
-module CIMI::Model
-
-  def self.register_as_root_entity!(name)
-    @root_entities ||= []
-    @root_entities << name
-    unless CIMI::Model::CloudEntryPoint.href_defined?(name)
-      CIMI::Model::CloudEntryPoint.send(:href, name.underscore)
-    end
-  end
-
-  def self.root_entities
-    @root_entities || []
-  end
-
-end
-
-class CIMI::Model::Base
-
-  #
-  # We keep the values of the attributes in a hash
-  #
-  attr_reader :attribute_values
-
-  # Keep the list of all attributes in an array +attributes+; for each
-  # attribute, we also define a getter and a setter to access/change the
-  # value for that attribute
-  class << self
-    def base_schema
-      @schema ||= CIMI::Model::Schema.new
-    end
-
-    def clone_base_schema
-      @schema_duped = true
-      @schema = Marshal::load(Marshal.dump(superclass.base_schema))
-    end
-
-    def base_schema_cloned?
-      @schema_duped
-    end
-
-    private :'clone_base_schema', :'base_schema_cloned?'
-
-    def inherited(child)
-      child.instance_eval do
-        def schema
-          base_schema_cloned? ? @schema : clone_base_schema
-        end
-      end
-    end
-
-    def add_attributes!(names, attr_klass, &block)
-      if self.respond_to? :schema
-        schema.add_attributes!(names, attr_klass, &block)
-      else
-        base_schema.add_attributes!(names, attr_klass, &block)
-      end
-      names.each do |name|
-        define_method(name) { @attribute_values[name] }
-        define_method(:"#{name}=") { |newval| @attribute_values[name] = newval }
-      end
-    end
-
-    # Return Array of links to current CIMI object
-    def all_uri(context)
-      self.all(context).map { |e| { :href => e.id } }
-    end
-  end
-
-  extend CIMI::Model::Schema::DSL
-
-  def [](a)
-    @attribute_values[a]
-  end
-
-  def []=(a, v)
-    @attribute_values[a] = v
-  end
-
-  #
-  # Factory methods
-  #
-  def initialize(values = {})
-    @attribute_values = values
-  end
-
-  # Construct a new object from the XML representation +xml+
-  def self.from_xml(text)
-    xml = XmlSimple.xml_in(text, :force_content => true)
-    model = self.new
-    @schema.from_xml(xml, model)
-    model
-  end
-
-  # Construct a new object
-  def self.from_json(text)
-    json = JSON::parse(text)
-    model = self.new
-    @schema.from_json(json, model)
-    model
-  end
-
-  #
-  # Serialize
-  #
-
-  def self.xml_tag_name
-    self.name.split("::").last
-  end
-
-  def self.to_json(model)
-    JSON::unparse(@schema.to_json(model))
-  end
-
-  def self.to_xml(model)
-    xml = @schema.to_xml(model)
-    xml["xmlns"] = "http://www.dmtf.org/cimi"
-    XmlSimple.xml_out(xml, :root_name => xml_tag_name)
-  end
-
-  def to_json
-    self.class.to_json(self)
-  end
-
-  def to_xml
-    self.class.to_xml(self)
-  end
-
-  #
-  # Common attributes for all resources
-  #
-  text :id, :name, :description, :created
-
-  # FIXME: this doesn't match with JSON
-  hash :property, :content => :value do
-    scalar :name
-  end
-
-  def self.act_as_root_entity(name=nil)
-    if name
-      name = name.to_s.camelize.pluralize
-    else
-      name = xml_tag_name.pluralize.uncapitalize
-    end
-    CIMI::Model.register_as_root_entity! name
-  end
-
-  def self.all(_self); find(:all, _self); end
-
-  def filter_by(filter_opts)
-    return self if filter_opts.nil?
-    return filter_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
-    case filter_opts
-      when /^([\w\_]+)$/ then filter_attributes([$1.intern])
-      when /^([\w\_]+)\[(\d+\-\d+)\]$/ then filter_by_arr_range($1.intern, $2)
-      when /^([\w\_]+)\[(\d+)\]$/ then filter_by_arr_index($1.intern, $2)
-      else self
-    end
-  end
-
-  private
-
-  def filter_attributes(attr_list)
-    attrs = attr_list.inject({}) do |result, attr|
-      result[attr] = self.send(attr) if self.respond_to?(attr)
-      result
-    end
-    self.class.new(attrs)
-  end
-
-  def filter_by_arr_index(attr, filter)
-    return self unless self.respond_to?(attr)
-    self.class.new(attr => [self.send(attr)[filter.to_i]])
-  end
-
-  def filter_by_arr_range(attr, filter)
-    return self unless self.respond_to?(attr)
-    filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
-    self.class.new(attr => self.send(attr)[filter])
-  end
-end
diff --git a/server/lib/cimi/model/cloud_entry_point.rb b/server/lib/cimi/model/cloud_entry_point.rb
deleted file mode 100644
index 5db94df..0000000
--- a/server/lib/cimi/model/cloud_entry_point.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
-
-  array :entity_metadata do
-    scalar :href
-  end
-
-  def self.create(context)
-    self.new(entities(context).merge({
-      :name => context.driver.name,
-      :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
-      :id => context.cloudEntryPoint_url,
-      :created => Time.now,
-      :entity_metadata => EntityMetadata.all_uri(context)
-    }))
-  end
-
-  # Return an Hash of the CIMI root entities used in CloudEntryPoint
-  def self.entities(context)
-    CIMI::Model.root_entities.inject({}) do |result, entity|
-      if context.respond_to? :"#{entity.underscore}_url"
-        result[entity.underscore] = { :href => context.send(:"#{entity.underscore}_url") }
-      end
-      result
-    end
-  end
-
-  private
-
-  def self.href_defined?(entity)
-    true if schema.attribute_names.include? entity.underscore
-  end
-
-end
diff --git a/server/lib/cimi/model/entity_metadata.rb b/server/lib/cimi/model/entity_metadata.rb
deleted file mode 100644
index bc20ff3..0000000
--- a/server/lib/cimi/model/entity_metadata.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-class CIMI::Model::EntityMetadata < CIMI::Model::Base
-
-text :type_uri
-
-  array :attributes do
-    scalar :name
-    scalar :namespace
-    scalar :type
-    scalar :required
-    scalar :constraints
-  end
-
-  array :operations do
-    scalar :name
-    scalar :uri
-    scalar :description
-    scalar :method
-    scalar :input_message
-    scalar :output_message
-  end
-
-  def self.find(id, context)
-    entity_metadata = []
-    if id == :all
-      CIMI::Model.root_entities.each do |entity|
-        entity_class = CIMI::Model.const_get("#{entity.singularize}")
-        entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?(:create_entity_metadata)
-      end
-      return entity_metadata
-    else
-      entity_class = CIMI::Model.const_get("#{id.camelize}")
-      if entity_class.respond_to?(:create_entity_metadata)
-        entity_class.create_entity_metadata(context)
-      end
-    end
-  end
-
-  def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
-    deltacloud_features = context.driver.features(dcloud_entity)
-    metadata_attributes = deltacloud_features.map{|f| attributes_from_feature(f)}
-    from_feature(cimi_entity, context, metadata_attributes.flatten!)
-  end
-
-  def includes_attribute?(attribute)
-    self.attributes.any?{|attr| attr[:name] == attribute}
-  end
-
-  private
-
-  def self.attributes_from_feature(feature)
-    feature.operations.first.params.inject([]) do |result, param|
-      result << {
-        :name=>(feature.name == :user_name ? :name : param[0]),
-        :type=> "xs:string",
-        :required=> (param[1] and param[1].optional?) ? "false" : "true",
-        :constraints=> (feature.constraints.empty? ? (feature.description.nil? ? "" : feature.description): feature.constraints)
-      }
-    end
-  end
-
-  def self.from_feature(cimi_entity, context, metadata_attributes)
-    self.new(:name => cimi_entity, :uri=>"#{context.entity_metadata_url}/#{cimi_entity.underscore}",
-             :type_uri=> context.send("#{cimi_entity.pluralize.underscore}_url"),
-             :attributes => metadata_attributes)
-  end
-
-end
diff --git a/server/lib/cimi/model/entity_metadata_collection.rb b/server/lib/cimi/model/entity_metadata_collection.rb
deleted file mode 100644
index 63db7f7..0000000
--- a/server/lib/cimi/model/entity_metadata_collection.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::EntityMetadataCollection < CIMI::Model::Base
-
-  array :entity_metadata do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.entity_metadata_url,
-      :name => 'default',
-      :created => Time.now,
-      :entity_metadata => EntityMetadata.all_uri(context)
-   )
-  end
-
-end
diff --git a/server/lib/cimi/model/errors.rb b/server/lib/cimi/model/errors.rb
deleted file mode 100644
index 7c090ed..0000000
--- a/server/lib/cimi/model/errors.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module CIMI::Model
-
-  class NotFound < StandardError
-    attr_accessor :code
-
-    def initialize
-      super("Requested Entity Not Found")
-      self.code = 404
-    end
-
-  end
-
-  class BadRequest < StandardError
-    attr_accessor :code
-    def initialize(msg="")
-      super(msg)
-      self.code=400
-    end
-  end
-
-  class NotImplemented < StandardError
-    attr_accessor :code
-
-    def initialize
-      super("Requested operation is not implemented by backend provider")
-      self.code = 501
-    end
-
-  end
-
-end
-
-
diff --git a/server/lib/cimi/model/machine.rb b/server/lib/cimi/model/machine.rb
deleted file mode 100644
index 939629a..0000000
--- a/server/lib/cimi/model/machine.rb
+++ /dev/null
@@ -1,229 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/models/instance_address'
-
-class CIMI::Model::Machine < CIMI::Model::Base
-
-  text :state
-  text :cpu
-
-  struct :memory do
-    scalar :quantity
-    scalar :units
-  end
-
-  href :event_log
-
-  array :disks do
-    struct :capacity do
-      scalar :quantity
-      scalar :units
-    end
-    scalar :format
-    scalar :attachment_point
-  end
-
-  array :volumes do
-    scalar :href
-    scalar :protocol
-    scalar :attachment_point
-  end
-
-  array :network_interfaces do
-    href :vsp
-    text :hostname, :mac_address, :state, :protocol, :allocation
-    text :address, :default_gateway, :dns, :max_transmission_unit
-  end
-
-  array :meters do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    instances = []
-    if id == :all
-      instances = context.driver.instances(context.credentials)
-      instances.map { |instance| from_instance(instance, context) }.compact
-    else
-      instance = context.driver.instance(context.credentials, :id => id)
-      raise CIMI::Model::NotFound unless instance
-      from_instance(instance, context)
-    end
-  end
-
-  def self.create_from_json(body, context)
-    json = JSON.parse(body)
-    hardware_profile_id = xml['machineTemplate']['machineConfig']["href"].split('/').last
-    image_id = xml['machineTemplate']['machineImage']["href"].split('/').last
-    instance = context.create_instance(context.credentials, image_id, { :hwp_id => hardware_profile_id })
-    from_instance(instance, context)
-  end
-
-  def self.create_from_xml(body, context)
-    xml = XmlSimple.xml_in(body)
-    machine_template = xml['machineTemplate'][0]
-    hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
-    image_id = machine_template['machineImage'][0]["href"].split('/').last
-    additional_params = {}
-    additional_params[:name] =xml['name'][0] if xml['name']
-    if machine_template.has_key? 'machineAdmin'
-      additional_params[:keyname] = machine_template['machineAdmin'][0]["href"].split('/').last
-    end
-    instance = context.driver.create_instance(context.credentials, image_id, {
-      :hwp_id => hardware_profile_id
-    }.merge(additional_params))
-    from_instance(instance, context)
-  end
-
-  def perform(action, context, &block)
-    begin
-      if context.driver.send(:"#{action.name}_instance", context.credentials, self.name)
-        block.callback :success
-      else
-        raise "Operation failed to execute on given Machine"
-      end
-    rescue => e
-      block.callback :failure, e.message
-    end
-  end
-
-  def self.delete!(id, context)
-    context.driver.destroy_instance(context.credentials, id)
-  end
-
-  def self.create_entity_metadata(context)
-    cimi_entity = self.name.split("::").last
-    metadata = EntityMetadata.metadata_from_deltacloud_features(cimi_entity, :instances, context)
-    unless metadata.includes_attribute?(:name)
-      metadata.attributes << {:name=>"name", :required=>"false",
-                   :constraints=>"Determined by the cloud provider", :type=>"xs:string"}
-    end
-    metadata
-  end
-
-  def self.attach_volumes(volumes, context)
-    volumes.each do |vol|
-      context.driver.attach_storage_volume(context.credentials,
-      {:id=>vol[:volume].name, :instance_id=>context.params[:id], :device=>vol[:attachment_point]})
-    end
-    self.find(context.params[:id], context)
-  end
-
-  def self.detach_volumes(volumes, context)
-    volumes.each do |vol|
-      context.driver.detach_storage_volume(context.credentials, {:id=>vol[:volume].name, :instance_id => context.params[:id]})
-    end
-    self.find(context.params[:id], context)
-  end
-
-  private
-
-  def self.from_instance(instance, context)
-    cpu =  memory = disks = (instance.instance_profile.id == "opaque")? "n/a" : nil
-    self.new(
-      :name => instance.id,
-      :description => instance.name,
-      :created => instance.launch_time,
-      :id => context.machine_url(instance.id),
-      :state => convert_instance_state(instance.state),
-      :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
-      :memory => memory || convert_instance_memory(instance.instance_profile, context),
-      :disks => disks || convert_instance_storage(instance.instance_profile, context),
-      :network_interfaces => convert_instance_addresses(instance),
-      :operations => convert_instance_actions(instance, context),
-      :volumes=>convert_storage_volumes(instance, context),
-      :property => convert_instance_properties(instance, context)
-    )
-  end
-
-  # FIXME: This will convert 'RUNNING' state to 'STARTED'
-  # which is defined in CIMI (p65)
-  #
-  def self.convert_instance_state(state)
-    ('RUNNING' == state) ? 'STARTED' : state
-  end
-
-  def self.convert_instance_properties(instance, context)
-    properties = []
-    properties << { :name => :machine_image, :value => context.machine_image_url(instance.image_id) }
-    if instance.respond_to? :keyname
-      properties << { :name => :machine_admin, :value => context.machine_admin_url(instance.keyname) }
-    end
-    properties
-  end
-
-  def self.convert_instance_cpu(profile, context)
-    cpu_override = profile.overrides.find { |p, v| p == :cpu }
-    if cpu_override.nil?
-      MachineConfiguration.find(profile.id, context).cpu
-    else
-      cpu_override[1]
-    end
-  end
-
-  def self.convert_instance_memory(profile, context)
-    machine_conf = MachineConfiguration.find(profile.name, context)
-    memory_override = profile.overrides.find { |p, v| p == :memory }
-    {
-      :quantity => memory_override.nil? ? machine_conf.memory[:quantity] : memory_override[1],
-      :units => machine_conf.memory[:units]
-    }
-  end
-
-  def self.convert_instance_storage(profile, context)
-    machine_conf = MachineConfiguration.find(profile.name, context)
-    storage_override = profile.overrides.find { |p, v| p == :storage }
-    [
-      { :capacity => {
-          :quantity => storage_override.nil? ? machine_conf.disks.first[:capacity][:quantity] : storage_override[1],
-          :units => machine_conf.disks.first[:capacity][:units]
-        }
-      }
-    ]
-  end
-
-  def self.convert_instance_addresses(instance)
-    (instance.public_addresses + instance.private_addresses).collect do |address|
-      {
-        :hostname => address.is_hostname? ? address : nil,
-        :mac_address => address.is_mac? ? address : nil,
-        :state => 'Active',
-        :protocol => 'IPv4',
-        :address => address.is_ipv4? ? address : nil,
-        :allocation => 'Static'
-      }
-    end
-  end
-
-  def self.convert_instance_actions(instance, context)
-    instance.actions.collect do |action|
-      action = :destroy if action == :delete # In CIMI destroy operation become delete
-      action = :restart if action == :reboot  # In CIMI reboot operation become restart
-      { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://www.dmtf.org/cimi/action/#{action}" }
-    end
-  end
-
-  def self.convert_storage_volumes(instance, context)
-    instance.storage_volumes ||= [] #deal with nilpointers
-    instance.storage_volumes.map{|vol| {:href=>context.volume_url(vol.keys.first),
-                                       :attachment_point=>vol.values.first} }
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_admin.rb b/server/lib/cimi/model/machine_admin.rb
deleted file mode 100644
index fed7c80..0000000
--- a/server/lib/cimi/model/machine_admin.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineAdmin < CIMI::Model::Base
-
-  text :username
-  text :password
-  text :key
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id == :all
-      keys = context.driver.keys(context.credentials)
-      keys.map { |key| from_key(key, context) }
-    else
-      key = context.driver.key(context.credentials, :id => id)
-      from_key(key, context)
-    end
-  end
-
-  def self.create_from_xml(body, context)
-    machine_admin = MachineAdmin.from_xml(body)
-    key = context.driver.create_key(context.credentials, :key_name => machine_admin.name)
-    from_key(key, context)
-  end
-
-  def self.delete!(id, context)
-    context.driver.destroy_key(context.credentials, :id => id)
-  end
-
-  private
-
-  def self.from_key(key, context)
-    self.new(
-      :name => key.id,
-      :username => key.username,
-      :password => key.is_password? ? key.password : key.fingerprint,
-      :key => key.is_key? ? key.pem_rsa_key : nil,
-      :id => context.machine_admin_url(key.id),
-      :created => Time.now
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_admin_collection.rb b/server/lib/cimi/model/machine_admin_collection.rb
deleted file mode 100644
index fd76a52..0000000
--- a/server/lib/cimi/model/machine_admin_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineAdminCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_admin
-
-  array :machine_admins do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_admins_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineAdminCollection",
-      :machine_admins => MachineAdmin.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_collection.rb b/server/lib/cimi/model/machine_collection.rb
deleted file mode 100644
index 27aa61b..0000000
--- a/server/lib/cimi/model/machine_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine
-
-  array :machines do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machines_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineCollection",
-      :machines => Machine.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_configuration.rb b/server/lib/cimi/model/machine_configuration.rb
deleted file mode 100644
index f9d98f2..0000000
--- a/server/lib/cimi/model/machine_configuration.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineConfiguration < CIMI::Model::Base
-
-  struct :memory do
-    scalar :quantity
-    scalar :units
-  end
-
-  text :cpu
-
-  array :disks do
-    struct :capacity do
-      scalar :quantity
-      scalar :units
-    end
-    scalar :format
-    scalar :attachment_point
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    profiles = []
-    if id == :all
-      profiles = context.driver.hardware_profiles(context.credentials)
-      profiles.map { |profile| from_hardware_profile(profile, context) }.compact
-    else
-      profile = context.driver.hardware_profile(context.credentials, id)
-      from_hardware_profile(profile, context)
-    end
-  end
-
-  private
-
-  def self.from_hardware_profile(profile, context)
-    # We accept just profiles with all properties set
-    return unless profile.memory or profile.cpu or profile.storage
-    memory = profile.memory.value || profile.memory.default
-    cpu = profile.cpu.value || profile.cpu.default
-    storage = profile.storage.value || profile.storage.default
-    machine_hash = {
-      :name => profile.name,
-      :description => "Machine Configuration with #{memory} #{profile.memory.unit} "+
-        "of memory and #{cpu} CPU",
-      :cpu => cpu,
-      :created => Time.now.to_s,  # FIXME: DC hardware_profile has no mention about created_at
-      :memory => { :quantity => profile.memory.value || profile.memory.default, :units => profile.memory.unit },
-      :disks => [ { :capacity => { :quantity => profile.storage.value || profile.storage.default, :units => profile.storage.unit } } ],
-      :id => context.machine_configuration_url(profile.name)
-    }
-    self.new(machine_hash)
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_configuration_collection.rb b/server/lib/cimi/model/machine_configuration_collection.rb
deleted file mode 100644
index 171acac..0000000
--- a/server/lib/cimi/model/machine_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineConfigurationCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_configuration
-
-  array :machine_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineConfigurationCollection",
-      :machine_configurations => MachineConfiguration.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_image.rb b/server/lib/cimi/model/machine_image.rb
deleted file mode 100644
index 7389475..0000000
--- a/server/lib/cimi/model/machine_image.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineImage < CIMI::Model::Base
-
-  href :image_location
-  text :image_data
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    images = []
-    if id == :all
-      images = context.driver.images(context.credentials)
-      images.map { |image| from_image(image, context) }
-    else
-      image = context.driver.image(context.credentials, :id => id)
-      from_image(image, context)
-    end
-  end
-
-  def self.from_image(image, context)
-    self.new(
-      :name => image.id,
-      :id => context.machine_image_url(image.id),
-      :description => image.description,
-      :created => Time.now.to_s,
-      :image_location => { :href => "#{context.driver.name}://#{image.id}" } # FIXME
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_image_collection.rb b/server/lib/cimi/model/machine_image_collection.rb
deleted file mode 100644
index b02ede7..0000000
--- a/server/lib/cimi/model/machine_image_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineImageCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_image
-
-  array :machine_images do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_images_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineImageCollection",
-      :machine_images => MachineImage.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/machine_template.rb b/server/lib/cimi/model/machine_template.rb
deleted file mode 100644
index 8a88052..0000000
--- a/server/lib/cimi/model/machine_template.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineTemplate < CIMI::Model::Base
-
-  href :machine_config
-  href :machine_image
-  href :machine_admin
-
-  array :volumes do
-    scalar :href
-    scalar :protocol
-    scalar :attachment_point
-  end
-
-  array :volume_templates do
-    scalar :href, :attachment_point, :protocol
-  end
-
-  array :network_interfaces do
-    href :vsp
-    text :hostname, :mac_address, :state, :protocol, :allocation
-    text :address, :default_gateway, :dns, :max_transmission_unit
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-end
diff --git a/server/lib/cimi/model/machine_template_collection.rb b/server/lib/cimi/model/machine_template_collection.rb
deleted file mode 100644
index e1e8d30..0000000
--- a/server/lib/cimi/model/machine_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::MachineTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :machine_template
-
-  array :machine_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.machine_template_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} MachineTemplateCollection",
-      :machine_templates => MachineTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/network.rb b/server/lib/cimi/model/network.rb
deleted file mode 100644
index cbfbae0..0000000
--- a/server/lib/cimi/model/network.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Network < CIMI::Model::Base
-
-  text :state
-
-  text :access
-
-  text :bandwidth_limit
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  href :routing_group
-
-  href :event_log
-
-  array :meters do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    networks=[]
-    if id==:all
-      networks = context.driver.networks(context.credentials, {:env=>context})
-    else
-      networks = context.driver.networks(context.credentials, {:id=>id, :env=>context})
-    end
-    networks
-  end
-
-  def self.create(request_body, context, type)
-    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false,"NormaliseSpace"=>2}) : JSON.parse(request_body)
-    if input["networkTemplate"]["href"] #template by reference
-      network_config, routing_group = get_by_reference(input, context)
-    else
-      if input["networkTemplate"]["networkConfig"]["href"] # configuration by reference
-        network_config = NetworkConfiguration.find(context.href_id(input["networkTemplate"]["networkConfig"]["href"],:network_configurations), context)
-      else #configuration by value
-        network_config = get_by_value(request_body, type)
-      end
-      routing_group = RoutingGroup.find(context.href_id(input["networkTemplate"]["routingGroup"]["href"], :routing_groups), context)
-    end
-    params = {:network_config => network_config, :routing_group => routing_group, :name=>input["name"], :description=>input["description"], :env=>context}
-    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
-    context.driver.create_network(context.credentials, params)
-  end
-
-  def self.delete!(id, context)
-    context.driver.delete_network(context.credentials, id)
-  end
-
-  def perform(action, context, &block)
-    begin
-      if context.driver.send(:"#{action.name}_network", context.credentials, self.name)
-        block.callback :success
-      else
-        raise "Operation #{action.name} failed to execute on the Network #{self.name} "
-      end
-    rescue => e
-      block.callback :failure, e.message
-    end
-  end
-
-  private
-
-  def self.get_by_reference(input, context)
-    network_template = NetworkTemplate.find(context.href_id(input["networkTemplate"]["href"], :network_templates), context)
-    network_config = NetworkConfiguration.find(context.href_id(network_template.network_config.href, :network_configurations), context)
-    routing_group = RoutingGroup.find(context.href_id(network_template.routing_group.href, :routing_groups), context)
-    return network_config, routing_group
-  end
-
-  def self.get_by_value(request_body, type)
-    if type == :xml
-      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
-      network_config = NetworkConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["networkTemplate"][0]["networkConfig"][0]))
-    else
-     json = JSON.parse(request_body)
-      network_config = NetworkConfiguration.from_json(JSON.generate(json["networkTemplate"]["networkConfig"]))
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/network_collection.rb b/server/lib/cimi/model/network_collection.rb
deleted file mode 100644
index 836d8e8..0000000
--- a/server/lib/cimi/model/network_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkCollection < CIMI::Model::Base
-
-  act_as_root_entity :network
-
-  array :networks do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.networks_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} NetworkCollection",
-      :networks => Network.all(context).map { |c| { :href => c.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/network_configuration.rb b/server/lib/cimi/model/network_configuration.rb
deleted file mode 100644
index 1b04548..0000000
--- a/server/lib/cimi/model/network_configuration.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkConfiguration < CIMI::Model::Base
-
-  text :access
-
-  text :bandwidth_limit
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    network_configs = []
-    if id==:all
-      network_configs = context.driver.network_configurations(context.credentials, {:env=>context})
-    else
-      network_configs = context.driver.network_configurations(context.credentials, {:env=>context, :id=>id})
-    end
-    network_configs
-  end
-
-  def self.create_from_xml(request_body, context)
-  end
-
-  def self.create_from_json(request_body, context)
-  end
-end
diff --git a/server/lib/cimi/model/network_configuration_collection.rb b/server/lib/cimi/model/network_configuration_collection.rb
deleted file mode 100644
index fd70047..0000000
--- a/server/lib/cimi/model/network_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkConfigurationCollection < CIMI::Model::Base
-
-  act_as_root_entity :network_configuration
-
-  array :network_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.network_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} NetworkConfigurationCollection",
-      :network_configurations => NetworkConfiguration.all(context).map { |c| { :href => c.id } }
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/network_template.rb b/server/lib/cimi/model/network_template.rb
deleted file mode 100644
index ce3b990..0000000
--- a/server/lib/cimi/model/network_template.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::NetworkTemplate < CIMI::Model::Base
-
-  href :network_config
-
-  href :routing_group
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    network_templates = []
-    if id==:all
-      network_templates = context.driver.network_templates(context.credentials, {:env=>context})
-    else
-      network_templates = context.driver.network_templates(context.credentials, {:env=>context, :id=>id})
-    end
-    network_templates
-  end
-
-end
diff --git a/server/lib/cimi/model/network_template_collection.rb b/server/lib/cimi/model/network_template_collection.rb
deleted file mode 100644
index 6b97b6e..0000000
--- a/server/lib/cimi/model/network_template_collection.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-class CIMI::Model::NetworkTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :network_template
-
-  array :network_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.network_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} NetworkTemplateCollection",
-      :network_templates => NetworkTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group.rb b/server/lib/cimi/model/routing_group.rb
deleted file mode 100644
index d26f4d7..0000000
--- a/server/lib/cimi/model/routing_group.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::RoutingGroup < CIMI::Model::Base
-
-  array :networks do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.routing_groups(context.credentials, {:env=>context})
-    else
-      context.driver.routing_groups(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group_collection.rb b/server/lib/cimi/model/routing_group_collection.rb
deleted file mode 100644
index 1546c80..0000000
--- a/server/lib/cimi/model/routing_group_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::RoutingGroupCollection < CIMI::Model::Base
-
-  act_as_root_entity :routing_group
-
-  array :routing_groups do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.routing_groups_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} RoutingGroupCollection",
-      :routing_groups => RoutingGroup.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group_template.rb b/server/lib/cimi/model/routing_group_template.rb
deleted file mode 100644
index 204a353..0000000
--- a/server/lib/cimi/model/routing_group_template.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::RoutingGroupTemplate < CIMI::Model::Base
-
-  array :networks do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.routing_group_templates(context.credentials, {:env=>context})
-    else
-      context.driver.routing_group_templates(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/routing_group_template_collection.rb b/server/lib/cimi/model/routing_group_template_collection.rb
deleted file mode 100644
index 5e7a9ba..0000000
--- a/server/lib/cimi/model/routing_group_template_collection.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-class CIMI::Model::RoutingGroupTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :routing_group_template
-
-  array :routing_group_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.routing_group_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} RoutingGroupTemplateCollection",
-      :routing_group_templates => RoutingGroupTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/schema.rb b/server/lib/cimi/model/schema.rb
deleted file mode 100644
index f301b69..0000000
--- a/server/lib/cimi/model/schema.rb
+++ /dev/null
@@ -1,277 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-# The smarts of converting from XML and JSON into internal objects
-class CIMI::Model::Schema
-
-  #
-  # Attributes describe how we extract values from XML/JSON
-  #
-  class Attribute
-    attr_reader :name, :xml_name, :json_name
-
-    def initialize(name, opts = {})
-      @name = name
-      @xml_name = (opts[:xml_name] || name).to_s.camelize(true)
-      @json_name = (opts[:json_name] || name).to_s.camelize(true)
-    end
-
-    def from_xml(xml, model)
-      model[@name] = xml[@xml_name].first if xml.has_key?(@xml_name)
-    end
-
-    def from_json(json, model)
-      model[@name] = json[@json_name]
-    end
-
-    def to_xml(model, xml)
-      xml[@xml_name] = [model[@name]] if model[@name]
-    end
-
-    def to_json(model, json)
-      json[@json_name] = model[@name] if model and model[@name]
-    end
-  end
-
-  class Scalar < Attribute
-    def initialize(name, opts)
-      @text = opts[:text]
-      if ! [nil, :nested, :direct].include?(@text)
-        raise "text option for scalar must be :nested or :direct"
-      end
-      super(name, opts)
-    end
-
-    def text?; @text; end
-
-    def nested_text?; @text == :nested; end
-
-    def from_xml(xml, model)
-      case @text
-        when :nested then model[@name] = xml[@xml_name].first["content"] if xml[@xml_name]
-        when :direct then model[@name] = xml["content"]
-        else model[@name] = xml[@xml_name]
-      end
-    end
-
-    def to_xml(model, xml)
-      return unless model
-      return unless model[@name]
-      case @text
-        when :nested then xml[@xml_name] = [{ "content" => model[@name] }]
-        when :direct then xml["content"] = model[@name]
-        else xml[@xml_name] = model[@name]
-      end
-    end
-  end
-
-  class Struct < Attribute
-    def initialize(name, opts, &block)
-      content = opts[:content]
-      super(name, opts)
-      @schema = CIMI::Model::Schema.new
-      @schema.instance_eval(&block) if block_given?
-      @schema.scalar(content, :text => :direct) if content
-    end
-
-    def from_xml(xml, model)
-      xml = xml.has_key?(xml_name) ? xml[xml_name].first : {}
-      model[name] = convert_from_xml(xml)
-    end
-
-    def from_json(json, model)
-      json = json.has_key?(json_name) ? json[json_name] : {}
-      model[name] = convert_from_json(json)
-    end
-
-    def to_xml(model, xml)
-      conv = convert_to_xml(model[name])
-      xml[xml_name] = [conv] unless conv.empty?
-    end
-
-    def to_json(model, json)
-      conv = convert_to_json(model[name])
-      json[json_name] = conv unless conv.empty?
-    end
-
-    def convert_from_xml(xml)
-      sub = struct.new
-      @schema.from_xml(xml, sub)
-      sub
-    end
-
-    def convert_from_json(json)
-      sub = struct.new
-      @schema.from_json(json, sub)
-      sub
-    end
-
-    def convert_to_xml(model)
-      xml = {}
-      @schema.to_xml(model, xml)
-      xml
-    end
-
-    def convert_to_json(model)
-      json = {}
-      @schema.to_json(model, json)
-      json
-    end
-
-    private
-    def struct
-      cname = "CIMI_#{json_name.upcase_first}"
-      if ::Struct.const_defined?(cname)
-        ::Struct.const_get(cname)
-      else
-        ::Struct.new("CIMI_#{json_name.upcase_first}",
-                     *@schema.attribute_names)
-      end
-    end
-  end
-
-  class Array < Attribute
-    # For an array :things, we collect all <thing/> elements (XmlSimple
-    # actually does the collecting)
-    def initialize(name, opts = {}, &block)
-      opts[:xml_name] = name.to_s.singularize unless opts[:xml_name]
-      super(name, opts)
-      @struct = Struct.new(name, opts, &block)
-    end
-
-    def from_xml(xml, model)
-      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
-    end
-
-    def from_json(json, model)
-      model[name] = (json[json_name] || []).map { |elt| @struct.convert_from_json(elt) }
-    end
-
-    def to_xml(model, xml)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
-      xml[xml_name] = ary unless ary.empty?
-    end
-
-    def to_json(model, json)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
-      json[json_name] = ary unless ary.empty?
-    end
-  end
-
-  class Hash < Attribute
-
-    def initialize(name, opts = {}, &block)
-      opts[:json_name] = name.to_s.pluralize unless opts[:json_name]
-      super(name, opts)
-      @struct = Struct.new(name, opts, &block)
-    end
-
-    def from_xml(xml, model)
-      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
-    end
-
-    def from_json(json, model)
-      model[name] = (json[json_name] || {}).inject([]) do |result,item|
-        result << @struct.convert_from_json({ 'name' => item[0], 'value' => item[1] })
-      end
-    end
-
-    def to_xml(model, xml)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
-      xml[xml_name] = ary unless ary.empty?
-    end
-
-    def to_json(model, json)
-      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
-      json[json_name] = ary.inject({}) { |result, item| result[item['name']] = item['value']; result } unless ary.empty?
-    end
-  end
-
-  #
-  # The actual Schema class
-  #
-  def initialize
-    @attributes = []
-  end
-
-  def from_xml(xml, model = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.from_xml(xml, model) }
-    model
-  end
-
-  def from_json(json, model = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.from_json(json, model) }
-    model
-  end
-
-  def to_xml(model, xml = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.to_xml(model, xml) }
-    xml
-  end
-
-  def to_json(model, json = {})
-    @attributes.freeze
-    @attributes.each { |attr| attr.to_json(model, json) }
-    json
-  end
-
-  def attribute_names
-    @attributes.map { |a| a.name }
-  end
-
-  #
-  # The DSL
-  #
-  # Requires that the class into which this is included has a
-  # +add_attributes!+ method
-  module DSL
-    def href(*args)
-      args.each { |arg| struct(arg) { scalar :href } }
-    end
-
-    def text(*args)
-      args.expand_opts!(:text => :nested)
-      scalar(*args)
-    end
-
-    def scalar(*args)
-      add_attributes!(args, Scalar)
-    end
-
-    def array(name, opts={}, &block)
-      add_attributes!([name, opts], Array, &block)
-    end
-
-    def struct(name, opts={}, &block)
-      add_attributes!([name, opts], Struct, &block)
-    end
-
-    def hash(name, opts={}, &block)
-      add_attributes!([name, opts], Hash, &block)
-    end
-  end
-
-  include DSL
-
-  def add_attributes!(args, attr_klass, &block)
-    raise "The schema has already been used to convert objects" if @attributes.frozen?
-    opts = args.extract_opts!
-    args.each { |arg| @attributes << attr_klass.new(arg, opts, &block) }
-  end
-end
diff --git a/server/lib/cimi/model/volume.rb b/server/lib/cimi/model/volume.rb
deleted file mode 100644
index 0a232d5..0000000
--- a/server/lib/cimi/model/volume.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::Volume < CIMI::Model::Base
-
-  struct :capacity do
-    scalar :quantity
-    scalar :units
-  end
-  text :bootable
-  text :supports_snapshots
-  array :snapshots do
-    scalar :ref
-  end
-  text :guest_interface
-  array :meters do
-    scalar :ref
-  end
-  href :eventlog
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    volumes = []
-    opts = ( id == :all ) ? {} : { :id => id }
-    volumes = self.driver.storage_volumes(context.credentials, opts)
-    volumes.collect!{ |volume| from_storage_volume(volume, context) }
-    return volumes.first unless volumes.length > 1
-    return volumes
-  end
-
-  def self.all(context); find(:all, context); end
-
-  def self.create_from_json(json_in, context)
-    json = JSON.parse(json_in)
-    volume_config_id = json["volumeTemplate"]["volumeConfig"]["href"].split("/").last
-    volume_image_id = (json["volumeTemplate"].has_key?("volumeImage") ?
-                json["volumeTemplate"]["volumeImage"]["href"].split("/").last  : nil)
-    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
-  end
-
-  def self.create_from_xml(xml_in, context)
-    xml = XmlSimple.xml_in(xml_in)
-    volume_config_id = xml["volumeTemplate"][0]["volumeConfig"][0]["href"].split("/").last
-    volume_image_id = (xml["volumeTemplate"][0].has_key?("volumeImage") ?
-             xml["volumeTemplate"][0]["volumeImage"][0]["href"].split("/").last  : nil)
-    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
-  end
-
-  def self.delete!(id, context)
-    context.driver.destroy_storage_volume(context.credentials, {:id=>id} )
-  end
-
-  def self.find_to_attach_from_json(json_in, context)
-    json = JSON.parse(json_in)
-    volumes = json["volumes"].map{|v| {:volume=>self.find(v["volume"]["href"].split("/volumes/").last, context),
-                                       :attachment_point=>v["attachmentPoint"]  }}
-  end
-
-  def self.find_to_attach_from_xml(xml_in, context)
-    xml = XmlSimple.xml_in(xml_in)
-    volumes = xml["volume"].map{|v| {:volume => self.find(v["href"].split("/volumes/").last, context),
-                                      :attachment_point=>v["attachmentPoint"] }}
-  end
-
-  private
-
-  def self.create_volume(params, context)
-    volume_config = VolumeConfiguration.find(params[:volume_config_id], context)
-    opts = {:capacity=>volume_config.capacity[:quantity], :snapshot_id=>params[:volume_image_id] }
-    storage_volume = self.driver.create_storage_volume(context.credentials, opts)
-    from_storage_volume(storage_volume, context)
-  end
-
-  def self.from_storage_volume(volume, context)
-    self.new( { :name => volume.id,
-                :description => volume.id,
-                :created => volume.created,
-                :id => context.volume_url(volume.id),
-                :capacity => { :quantity=>volume.capacity, :units=>"gibibyte"  }, #FIXME... units will vary
-                :bootable => "false", #fixme ... will vary... ec2 doesn't expose this
-                :supports_snapshots => "true", #fixme, will vary (true for ec2)
-                :snapshots => [], #fixme...
-                :guest_interface => "",
-                :eventlog => {:href=> "http://eventlogs"},#FIXME
-                :meters => []
-            } )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_collection.rb b/server/lib/cimi/model/volume_collection.rb
deleted file mode 100644
index d5053c7..0000000
--- a/server/lib/cimi/model/volume_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume
-
-  array :volumes do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volumes_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeCollection",
-      :volumes => Volume.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_configuration.rb b/server/lib/cimi/model/volume_configuration.rb
deleted file mode 100644
index 75b37ea..0000000
--- a/server/lib/cimi/model/volume_configuration.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
-
-  text :format
-  struct :capacity do
-    scalar :quantity
-    scalar :units
-  end
-  text :supports_snapshots
-  text :guest_interface
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    volume_configs = []
-    if id == :all
-      #ec2 ebs volumes can 1gb..1tb
-      (1..1000).each do |size|
-        volume_configs << create(size, context)
-      end
-    else
-      volume_configs << create(id, context)
-      return volume_configs.first
-    end
-    return volume_configs
-  end
-
-
-  def self.all(context); find(:all, context); end
-
-  private
-
-  def self.create(size, context)
-    self.new( {
-                :id => context.volume_configuration_url(size),
-                :name => size,
-                :description => "volume configuration with #{size} GiB",
-                :created => Time.now.to_s,
-                :capacity => {:quantity=>size, :units=>"gibibytes"},
-                :supports_snapshots => "true"
-                # FIXME :guest_interface => "NFS"
-            } )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_configuration_collection.rb b/server/lib/cimi/model/volume_configuration_collection.rb
deleted file mode 100644
index ace31bf..0000000
--- a/server/lib/cimi/model/volume_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeConfigurationCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume_configuration
-
-  array :volume_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volume_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeConfigurationCollection",
-      :volume_configurations => VolumeConfiguration.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_image.rb b/server/lib/cimi/model/volume_image.rb
deleted file mode 100644
index 03cc7fd..0000000
--- a/server/lib/cimi/model/volume_image.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeImage < CIMI::Model::Base
-
-  href :image_location
-  text :image_data
-  text :bootable
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    storage_snapshots = []
-    opts = ( id==:all  ) ? {}  : { :id=>id }
-    storage_snapshots = self.driver.storage_snapshots(context.credentials, opts)
-    storage_snapshots.collect!{ |snapshot| from_storage_snapshot(snapshot, context) }
-    return storage_snapshots.first unless storage_snapshots.length > 1
-    return storage_snapshots
-  end
-
-  def self.all(context); find(:all, context); end
-
-  private
-
-  def self.from_storage_snapshot(snapshot, context)
-    self.new( {
-               :name => snapshot.id,
-               :description => snapshot.id,
-               :created => snapshot.created,
-               :id => context.volume_image_url(snapshot.id),
-               :image_location => {:href=>context.volume_url(snapshot.storage_volume_id)},
-               :bootable => "false"  #FIXME
-            } )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_image_collection.rb b/server/lib/cimi/model/volume_image_collection.rb
deleted file mode 100644
index 0172c04..0000000
--- a/server/lib/cimi/model/volume_image_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeImageCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume_image
-
-  array :volume_images do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volume_images_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeImageCollection",
-      :volume_images => VolumeImage.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/volume_template.rb b/server/lib/cimi/model/volume_template.rb
deleted file mode 100644
index b9c82db..0000000
--- a/server/lib/cimi/model/volume_template.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeTemplate < CIMI::Model::Base
-
-  href :volume_config
-  href :volume_image
-  array :operations do
-    scalar :rel, :href
-  end
-end
diff --git a/server/lib/cimi/model/volume_template_collection.rb b/server/lib/cimi/model/volume_template_collection.rb
deleted file mode 100644
index 6b6e4ac..0000000
--- a/server/lib/cimi/model/volume_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VolumeTemplateCollection < CIMI::Model::Base
-
-  act_as_root_entity :volume_template
-
-  array :volume_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.volume_template_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VolumeTemplateCollection",
-      :volume_templates => VolumeTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp.rb b/server/lib/cimi/model/vsp.rb
deleted file mode 100644
index 40a526f..0000000
--- a/server/lib/cimi/model/vsp.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSP < CIMI::Model::Base
-
-  text :state
-
-  href :network
-
-  text :bandwidth_reservation
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  href :event_log
-
-  array :meters do
-    scalar :href
-  end
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.vsps(context.credentials, {:env=>context})
-    else
-      context.driver.vsps(context.credentials, {:id=>id, :env=>context})
-    end
-  end
-
-  def self.create(request_body, context, type)
-    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
-    if input["vspTemplate"]["href"] #template by reference
-      vsp_config, network = get_by_reference(input, context)
-    else
-      if input["vspTemplate"]["vspConfig"]["href"] # configuration by reference
-        vsp_config = VSPConfiguration.find(context.href_id(input["vspTemplate"]["vspConfig"]["href"],:vsp_configurations), context)
-      else #configuration by value
-        vsp_config = get_by_value(request_body, type)
-      end
-      network = Network.find(context.href_id(input["vspTemplate"]["network"]["href"], :networks), context)
-    end
-    params = {:vsp_config => vsp_config, :network => network, :name=>input["name"], :description=>input["description"], :env=>context}
-    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
-    context.driver.create_vsp(context.credentials, params)
-  end
-
-  def self.delete!(id, context)
-    context.driver.delete_vsp(context.credentials, id)
-  end
-
-  def perform(action, context, &block)
-    begin
-      if context.driver.send(:"#{action.name}_vsp", context.credentials, self.name)
-        block.callback :success
-      else
-        raise "Operation #{action.name} failed to execute on the VSP #{self.name} "
-      end
-    rescue => e
-      block.callback :failure, e.message
-    end
-  end
-
-
-  private
-
-  def self.get_by_reference(input, context)
-    vsp_template = VSPTemplate.find(context.href_id(input["vspTemplate"]["href"], :vsp_templates), context)
-    vsp_config = VSPConfiguration.find(context.href_id(vsp_template.vsp_config.href, :vsp_configurations), context)
-    network = Network.find(context.href_id(vsp_template.network.href, :networks), context)
-    return vsp_config, network
-  end
-
-  def self.get_by_value(request_body, type)
-    if type == :xml
-      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
-      vsp_config = VSPConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["vspTemplate"][0]["vspConfig"][0]))
-    else
-     json = JSON.parse(request_body)
-      vsp_config = VSPConfiguration.from_json(JSON.generate(json["vspTemplate"]["vspConfig"]))
-    end
-  end
-end
diff --git a/server/lib/cimi/model/vsp_collection.rb b/server/lib/cimi/model/vsp_collection.rb
deleted file mode 100644
index 6f659e1..0000000
--- a/server/lib/cimi/model/vsp_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPCollection < CIMI::Model::Base
-
-  CIMI::Model.register_as_root_entity! "VSPs"
-
-  array :vsps do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.vsps_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VSPCollection",
-      :vsps => VSP.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_configuration.rb b/server/lib/cimi/model/vsp_configuration.rb
deleted file mode 100644
index c9a9bf3..0000000
--- a/server/lib/cimi/model/vsp_configuration.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPConfiguration < CIMI::Model::Base
-
-  text :bandwidth_reservation
-
-  text :traffic_priority
-
-  text :max_traffic_delay
-
-  text :max_traffic_loss
-
-  text :max_traffic_jitter
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.vsp_configurations(context.credentials, {:env=>context})
-    else
-      context.driver.vsp_configurations(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_configuration_collection.rb b/server/lib/cimi/model/vsp_configuration_collection.rb
deleted file mode 100644
index addff1c..0000000
--- a/server/lib/cimi/model/vsp_configuration_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPConfigurationCollection < CIMI::Model::Base
-
-  CIMI::Model.register_as_root_entity! "VSPConfigurations"
-
-  array :vsp_configurations do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.vsp_configurations_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VSPConfigurationCollection",
-      :vsp_configurations => VSPConfiguration.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_template.rb b/server/lib/cimi/model/vsp_template.rb
deleted file mode 100644
index f1b8078..0000000
--- a/server/lib/cimi/model/vsp_template.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPTemplate < CIMI::Model::Base
-
-  href :network
-
-  href :vsp_config
-
-  array :operations do
-    scalar :rel, :href
-  end
-
-  def self.find(id, context)
-    if id==:all
-      context.driver.vsp_templates(context.credentials, {:env=>context})
-    else
-      context.driver.vsp_templates(context.credentials, {:env=>context, :id=>id})
-    end
-  end
-
-end
diff --git a/server/lib/cimi/model/vsp_template_collection.rb b/server/lib/cimi/model/vsp_template_collection.rb
deleted file mode 100644
index 4acb74e..0000000
--- a/server/lib/cimi/model/vsp_template_collection.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-class CIMI::Model::VSPTemplateCollection < CIMI::Model::Base
-
-  CIMI::Model.register_as_root_entity! "VSPTemplates"
-
-  array :vsp_templates do
-    scalar :href
-  end
-
-  def self.default(context)
-    self.new(
-      :id => context.vsp_templates_url,
-      :name => 'default',
-      :created => Time.now,
-      :description => "#{context.driver.name.capitalize} VSPTemplateCollection",
-      :vsp_templates => VSPTemplate.all_uri(context)
-    )
-  end
-
-end
diff --git a/server/lib/cimi/models/action.rb b/server/lib/cimi/models/action.rb
new file mode 100644
index 0000000..c1c9908
--- /dev/null
+++ b/server/lib/cimi/models/action.rb
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Action < CIMI::Model::Base
+
+  text :action
+
+  def name
+    action.split('/').last.strip.intern
+  end
+
+end
diff --git a/server/lib/cimi/models/address.rb b/server/lib/cimi/models/address.rb
new file mode 100644
index 0000000..f9e10a1
--- /dev/null
+++ b/server/lib/cimi/models/address.rb
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Address < CIMI::Model::Base
+
+  text :ip
+
+  text :hostname
+
+  text :allocation
+
+  text :default_gateway
+
+  text :dns
+
+  text :mac_address
+
+  text :protocol
+
+  text :mask
+
+  href :network
+
+  href :resource
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.addresses(context.credentials, {:env=>context})
+    else
+      context.driver.addresses(context.credentials, {:id=>id, :env=>context})
+    end
+  end
+
+  def self.create(request_body, context, type)
+    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
+    if input["addressTemplate"]["href"] #by reference
+      address_template = CIMI::Model::AddressTemplate.find(context.href_id(input["addressTemplate"]["href"], :address_templates), context)
+    else
+      case type
+        when :json
+          address_template = CIMI::Model::AddressTemplate.from_json(JSON.generate(input["addressTemplate"]))
+        when :xml
+          xml = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
+          address_template = CIMI::Model::AddressTemplate.from_xml(XmlSimple.xml_out(xml["addressTemplate"][0]))
+      end
+    end
+    params = {:name=>input["name"], :description=>input["description"], :address_template=>address_template, :env=>context }
+    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
+    context.driver.create_address(context.credentials, params)
+  end
+
+  def self.delete!(id, context)
+    context.driver.delete_address(context.credentials, id)
+  end
+
+end
diff --git a/server/lib/cimi/models/address_collection.rb b/server/lib/cimi/models/address_collection.rb
new file mode 100644
index 0000000..eef6c51
--- /dev/null
+++ b/server/lib/cimi/models/address_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::AddressCollection < CIMI::Model::Base
+
+  act_as_root_entity :address
+
+  array :addresses do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.addresses_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} AddressCollection",
+      :addresses => CIMI::Model::Address.all(context).map { |addr| { :href => addr.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/address_template.rb b/server/lib/cimi/models/address_template.rb
new file mode 100644
index 0000000..9d2c409
--- /dev/null
+++ b/server/lib/cimi/models/address_template.rb
@@ -0,0 +1,54 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::AddressTemplate < CIMI::Model::Base
+
+  text :ip
+
+  text :hostname
+
+  text :allocation
+
+  text :default_gateway
+
+  text :dns
+
+  text :mac_address
+
+  text :protocol
+
+  text :mask
+
+  href :network
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.address_templates(context.credentials, {:env=>context})
+    else
+      context.driver.address_templates(context.credentials, {:id=>id, :env=>context})
+    end
+  end
+
+  def self.create(request_body, context, type)
+  end
+
+  def self.delete!(id, context)
+  end
+
+end
diff --git a/server/lib/cimi/models/address_template_collection.rb b/server/lib/cimi/models/address_template_collection.rb
new file mode 100644
index 0000000..3bb95cd
--- /dev/null
+++ b/server/lib/cimi/models/address_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::AddressTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :address_template
+
+  array :address_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.address_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} AddressTemplateCollection",
+      :address_templates => CIMI::Model::AddressTemplate.all(context).map { |addr| { :href => addr.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb
new file mode 100644
index 0000000..16812ac
--- /dev/null
+++ b/server/lib/cimi/models/base.rb
@@ -0,0 +1,249 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require 'xmlsimple'
+require 'json'
+
+# The base class for any CIMI object that we either read from a request or
+# write as a response. This class handles serializing/deserializing XML and
+# JSON into a common form.
+#
+# == Defining the schema
+#
+# The conversion of XML and JSON into internal objects is based on a schema
+# that is defined through a DSL:
+#
+#   class Machine < CIMI::Model::Base
+#     text :status
+#     href :meter
+#     array :volumes do
+#       scalar :href, :attachment_point, :protocol
+#     end
+#   end
+#
+# The DSL automatically takes care of converting identifiers from their
+# underscored form to the camel-cased form used by CIMI. The above class
+# can be used in the following way:
+#
+#   machine = Machine.from_xml(some_xml)
+#   if machine.status == "UP"
+#     ...
+#   end
+#   sda = machine.volumes.find { |v| v.attachment_point == "/dev/sda" }
+#   handle_meter(machine.meter.href)
+#
+# The keywords for the DSL are
+#   [scalar(names, ...)]
+#     Define a scalar attribute; in JSON, this is represented as a string
+#     property. In XML, this can be represented in a number of ways,
+#     depending on whether the option :text is set:
+#       * :text not set: attribute on the enclosing element
+#       * :text == :direct: the text content of the enclosing element
+#       * :text == :nested: the text content of an element +<name>...</name>+
+#   [text(names)]
+#     A shorthand for +scalar(names, :text => :nested)+, i.e., for
+#     attributes that in XML are represented by their own tags
+#   [href(name)]
+#     A shorthand for +struct name { scalar :href }+; in JSON, this is
+#     represented as +{ name: { "href": string } }+, and in XML as +<name
+#     href="..."/>+
+#   [struct(name, opts, &block)]
+#     A structured subobject; the block defines the schema of the
+#     subobject. The +:content+ option can be used to specify the attribute
+#     that should receive the content of hte corresponding XML element
+#   [array(name, opts, &block)]
+#     An array of structured subobjects; the block defines the schema of
+#     the subobjects.
+
+module CIMI::Model
+
+  def self.register_as_root_entity!(name)
+    @root_entities ||= []
+    @root_entities << name
+    unless CIMI::Model::CloudEntryPoint.href_defined?(name)
+      CIMI::Model::CloudEntryPoint.send(:href, name.underscore)
+    end
+  end
+
+  def self.root_entities
+    @root_entities || []
+  end
+
+end
+
+class CIMI::Model::Base
+
+  #
+  # We keep the values of the attributes in a hash
+  #
+  attr_reader :attribute_values
+
+  # Keep the list of all attributes in an array +attributes+; for each
+  # attribute, we also define a getter and a setter to access/change the
+  # value for that attribute
+  class << self
+    def base_schema
+      @schema ||= CIMI::Model::Schema.new
+    end
+
+    def clone_base_schema
+      @schema_duped = true
+      @schema = Marshal::load(Marshal.dump(superclass.base_schema))
+    end
+
+    def base_schema_cloned?
+      @schema_duped
+    end
+
+    private :'clone_base_schema', :'base_schema_cloned?'
+
+    def inherited(child)
+      child.instance_eval do
+        def schema
+          base_schema_cloned? ? @schema : clone_base_schema
+        end
+      end
+    end
+
+    def add_attributes!(names, attr_klass, &block)
+      if self.respond_to? :schema
+        schema.add_attributes!(names, attr_klass, &block)
+      else
+        base_schema.add_attributes!(names, attr_klass, &block)
+      end
+      names.each do |name|
+        define_method(name) { @attribute_values[name] }
+        define_method(:"#{name}=") { |newval| @attribute_values[name] = newval }
+      end
+    end
+
+    # Return Array of links to current CIMI object
+    def all_uri(context)
+      self.all(context).map { |e| { :href => e.id } }
+    end
+  end
+
+  extend CIMI::Model::Schema::DSL
+
+  def [](a)
+    @attribute_values[a]
+  end
+
+  def []=(a, v)
+    @attribute_values[a] = v
+  end
+
+  #
+  # Factory methods
+  #
+  def initialize(values = {})
+    @attribute_values = values
+  end
+
+  # Construct a new object from the XML representation +xml+
+  def self.from_xml(text)
+    xml = XmlSimple.xml_in(text, :force_content => true)
+    model = self.new
+    @schema.from_xml(xml, model)
+    model
+  end
+
+  # Construct a new object
+  def self.from_json(text)
+    json = JSON::parse(text)
+    model = self.new
+    @schema.from_json(json, model)
+    model
+  end
+
+  #
+  # Serialize
+  #
+
+  def self.xml_tag_name
+    self.name.split("::").last
+  end
+
+  def self.to_json(model)
+    JSON::unparse(@schema.to_json(model))
+  end
+
+  def self.to_xml(model)
+    xml = @schema.to_xml(model)
+    xml["xmlns"] = "http://www.dmtf.org/cimi"
+    XmlSimple.xml_out(xml, :root_name => xml_tag_name)
+  end
+
+  def to_json
+    self.class.to_json(self)
+  end
+
+  def to_xml
+    self.class.to_xml(self)
+  end
+
+  #
+  # Common attributes for all resources
+  #
+  text :id, :name, :description, :created
+
+  # FIXME: this doesn't match with JSON
+  hash :property, :content => :value do
+    scalar :name
+  end
+
+  def self.act_as_root_entity(name=nil)
+    if name
+      name = name.to_s.camelize.pluralize
+    else
+      name = xml_tag_name.pluralize.uncapitalize
+    end
+    CIMI::Model.register_as_root_entity! name
+  end
+
+  def self.all(_self); find(:all, _self); end
+
+  def filter_by(filter_opts)
+    return self if filter_opts.nil?
+    return filter_attributes(filter_opts.split(',').map{ |a| a.intern }) if filter_opts.include? ','
+    case filter_opts
+      when /^([\w\_]+)$/ then filter_attributes([$1.intern])
+      when /^([\w\_]+)\[(\d+\-\d+)\]$/ then filter_by_arr_range($1.intern, $2)
+      when /^([\w\_]+)\[(\d+)\]$/ then filter_by_arr_index($1.intern, $2)
+      else self
+    end
+  end
+
+  private
+
+  def filter_attributes(attr_list)
+    attrs = attr_list.inject({}) do |result, attr|
+      result[attr] = self.send(attr) if self.respond_to?(attr)
+      result
+    end
+    self.class.new(attrs)
+  end
+
+  def filter_by_arr_index(attr, filter)
+    return self unless self.respond_to?(attr)
+    self.class.new(attr => [self.send(attr)[filter.to_i]])
+  end
+
+  def filter_by_arr_range(attr, filter)
+    return self unless self.respond_to?(attr)
+    filter = filter.split('-').inject { |s,e| s.to_i..e.to_i }
+    self.class.new(attr => self.send(attr)[filter])
+  end
+end
diff --git a/server/lib/cimi/models/cloud_entry_point.rb b/server/lib/cimi/models/cloud_entry_point.rb
new file mode 100644
index 0000000..ffe1ef5
--- /dev/null
+++ b/server/lib/cimi/models/cloud_entry_point.rb
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::CloudEntryPoint < CIMI::Model::Base
+
+  array :entity_metadata do
+    scalar :href
+  end
+
+  def self.create(context)
+    self.new(entities(context).merge({
+      :name => context.driver.name,
+      :description => "Cloud Entry Point for the Deltacloud #{context.driver.name} driver",
+      :id => context.cloudEntryPoint_url,
+      :created => Time.now,
+      :entity_metadata => CIMI::Model::EntityMetadata.all_uri(context)
+    }))
+  end
+
+  # Return an Hash of the CIMI root entities used in CloudEntryPoint
+  def self.entities(context)
+    CIMI::Model.root_entities.inject({}) do |result, entity|
+      result[entity.underscore] = { :href => context.send(:"#{entity.underscore}_url") }
+      result
+    end
+  end
+
+  private
+
+  def self.href_defined?(entity)
+    true if schema.attribute_names.include? entity.underscore
+  end
+
+end
diff --git a/server/lib/cimi/models/entity_metadata.rb b/server/lib/cimi/models/entity_metadata.rb
new file mode 100644
index 0000000..5455c75
--- /dev/null
+++ b/server/lib/cimi/models/entity_metadata.rb
@@ -0,0 +1,84 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class CIMI::Model::EntityMetadata < CIMI::Model::Base
+
+  text :type_uri
+
+  array :attributes do
+    scalar :name
+    scalar :namespace
+    scalar :type
+    scalar :required
+    scalar :constraints
+  end
+
+  array :operations do
+    scalar :name
+    scalar :uri
+    scalar :description
+    scalar :method
+    scalar :input_message
+    scalar :output_message
+  end
+
+  def self.find(id, context)
+    entity_metadata = []
+    if id == :all
+      CIMI::Model.root_entities.each do |entity|
+        entity_class = CIMI::Model.const_get("#{entity.singularize}")
+        entity_metadata << entity_class.create_entity_metadata(context) if entity_class.respond_to?(:create_entity_metadata)
+      end
+      return entity_metadata
+    else
+      entity_class = CIMI::Model.const_get("#{id.camelize}")
+      if entity_class.respond_to?(:create_entity_metadata)
+        entity_class.create_entity_metadata(context)
+      end
+    end
+  end
+
+  def self.metadata_from_deltacloud_features(cimi_entity, dcloud_entity, context)
+    deltacloud_features = context.driver.class.features_for(dcloud_entity)
+    metadata_attributes = deltacloud_features.map{|f| attributes_from_feature(f)}
+    from_feature(cimi_entity, context, metadata_attributes.flatten!)
+  end
+
+  def includes_attribute?(attribute)
+    self.attributes.any?{|attr| attr[:name] == attribute}
+  end
+
+  private
+
+  def self.attributes_from_feature(feature)
+    feature = CIMI::FakeCollection.feature(feature)
+    feature.operations.first.params_array.map do |p|
+      {
+        :name=> p.name,
+        :type=> "xs:string",
+        :required=> p.required? ? "true" : "false",
+        :constraints=> (feature.constraints.empty? ? (feature.description.nil? ? "" : feature.description): feature.constraints)
+      }
+    end
+  end
+
+  def self.from_feature(cimi_entity, context, metadata_attributes)
+    self.new(:name => cimi_entity, :uri=>"#{context.entity_metadata_url}/#{cimi_entity.underscore}",
+             :type_uri=> context.send("#{cimi_entity.pluralize.underscore}_url"),
+             :attributes => metadata_attributes)
+  end
+
+end
diff --git a/server/lib/cimi/models/entity_metadata_collection.rb b/server/lib/cimi/models/entity_metadata_collection.rb
new file mode 100644
index 0000000..595b502
--- /dev/null
+++ b/server/lib/cimi/models/entity_metadata_collection.rb
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::EntityMetadataCollection < CIMI::Model::Base
+
+  array :entity_metadata do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.entity_metadata_url,
+      :name => 'default',
+      :created => Time.now,
+      :entity_metadata => CIMI::Model::EntityMetadata.all_uri(context)
+   )
+  end
+
+end
diff --git a/server/lib/cimi/models/errors.rb b/server/lib/cimi/models/errors.rb
new file mode 100644
index 0000000..7c090ed
--- /dev/null
+++ b/server/lib/cimi/models/errors.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Model
+
+  class NotFound < StandardError
+    attr_accessor :code
+
+    def initialize
+      super("Requested Entity Not Found")
+      self.code = 404
+    end
+
+  end
+
+  class BadRequest < StandardError
+    attr_accessor :code
+    def initialize(msg="")
+      super(msg)
+      self.code=400
+    end
+  end
+
+  class NotImplemented < StandardError
+    attr_accessor :code
+
+    def initialize
+      super("Requested operation is not implemented by backend provider")
+      self.code = 501
+    end
+
+  end
+
+end
+
+
diff --git a/server/lib/cimi/models/machine.rb b/server/lib/cimi/models/machine.rb
new file mode 100644
index 0000000..0540bd8
--- /dev/null
+++ b/server/lib/cimi/models/machine.rb
@@ -0,0 +1,227 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Machine < CIMI::Model::Base
+
+  text :state
+  text :cpu
+
+  struct :memory do
+    scalar :quantity
+    scalar :units
+  end
+
+  href :event_log
+
+  array :disks do
+    struct :capacity do
+      scalar :quantity
+      scalar :units
+    end
+    scalar :format
+    scalar :attachment_point
+  end
+
+  array :volumes do
+    scalar :href
+    scalar :protocol
+    scalar :attachment_point
+  end
+
+  array :network_interfaces do
+    href :vsp
+    text :hostname, :mac_address, :state, :protocol, :allocation
+    text :address, :default_gateway, :dns, :max_transmission_unit
+  end
+
+  array :meters do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    instances = []
+    if id == :all
+      instances = context.driver.instances(context.credentials)
+      instances.map { |instance| from_instance(instance, context) }.compact
+    else
+      instance = context.driver.instance(context.credentials, :id => id)
+      raise CIMI::Model::NotFound unless instance
+      from_instance(instance, context)
+    end
+  end
+
+  def self.create_from_json(body, context)
+    json = JSON.parse(body)
+    hardware_profile_id = xml['machineTemplate']['machineConfig']["href"].split('/').last
+    image_id = xml['machineTemplate']['machineImage']["href"].split('/').last
+    instance = context.create_instance(context.credentials, image_id, { :hwp_id => hardware_profile_id })
+    from_instance(instance, context)
+  end
+
+  def self.create_from_xml(body, context)
+    xml = XmlSimple.xml_in(body)
+    machine_template = xml['machineTemplate'][0]
+    hardware_profile_id = machine_template['machineConfig'][0]["href"].split('/').last
+    image_id = machine_template['machineImage'][0]["href"].split('/').last
+    additional_params = {}
+    additional_params[:name] =xml['name'][0] if xml['name']
+    if machine_template.has_key? 'machineAdmin'
+      additional_params[:keyname] = machine_template['machineAdmin'][0]["href"].split('/').last
+    end
+    instance = context.driver.create_instance(context.credentials, image_id, {
+      :hwp_id => hardware_profile_id
+    }.merge(additional_params))
+    from_instance(instance, context)
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_instance", context.credentials, self.name)
+        block.callback :success
+      else
+        raise "Operation failed to execute on given Machine"
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_instance(context.credentials, id)
+  end
+
+  def self.create_entity_metadata(context)
+    cimi_entity = self.name.split("::").last
+    metadata = CIMI::Model::EntityMetadata.metadata_from_deltacloud_features(cimi_entity, :instances, context)
+    unless metadata.includes_attribute?(:name)
+      metadata.attributes << {:name=>"name", :required=>"false",
+                   :constraints=>"Determined by the cloud provider", :type=>"xs:string"}
+    end
+    metadata
+  end
+
+  def self.attach_volumes(volumes, context)
+    volumes.each do |vol|
+      context.driver.attach_storage_volume(context.credentials,
+      {:id=>vol[:volume].name, :instance_id=>context.params[:id], :device=>vol[:attachment_point]})
+    end
+    self.find(context.params[:id], context)
+  end
+
+  def self.detach_volumes(volumes, context)
+    volumes.each do |vol|
+      context.driver.detach_storage_volume(context.credentials, {:id=>vol[:volume].name, :instance_id => context.params[:id]})
+    end
+    self.find(context.params[:id], context)
+  end
+
+  private
+
+  def self.from_instance(instance, context)
+    cpu =  memory = disks = (instance.instance_profile.id == "opaque")? "n/a" : nil
+    self.new(
+      :name => instance.id,
+      :description => instance.name,
+      :created => instance.launch_time,
+      :id => context.machine_url(instance.id),
+      :state => convert_instance_state(instance.state),
+      :cpu => cpu || convert_instance_cpu(instance.instance_profile, context),
+      :memory => memory || convert_instance_memory(instance.instance_profile, context),
+      :disks => disks || convert_instance_storage(instance.instance_profile, context),
+      :network_interfaces => convert_instance_addresses(instance),
+      :operations => convert_instance_actions(instance, context),
+      :volumes=>convert_storage_volumes(instance, context),
+      :property => convert_instance_properties(instance, context)
+    )
+  end
+
+  # FIXME: This will convert 'RUNNING' state to 'STARTED'
+  # which is defined in CIMI (p65)
+  #
+  def self.convert_instance_state(state)
+    ('RUNNING' == state) ? 'STARTED' : state
+  end
+
+  def self.convert_instance_properties(instance, context)
+    properties = []
+    properties << { :name => :machine_image, :value => context.machine_image_url(instance.image_id) }
+    if instance.respond_to? :keyname
+      properties << { :name => :machine_admin, :value => context.machine_admin_url(instance.keyname) }
+    end
+    properties
+  end
+
+  def self.convert_instance_cpu(profile, context)
+    cpu_override = profile.overrides.find { |p, v| p == :cpu }
+    if cpu_override.nil?
+      CIMI::Model::MachineConfiguration.find(profile.id, context).cpu
+    else
+      cpu_override[1]
+    end
+  end
+
+  def self.convert_instance_memory(profile, context)
+    machine_conf = CIMI::Model::MachineConfiguration.find(profile.name, context)
+    memory_override = profile.overrides.find { |p, v| p == :memory }
+    {
+      :quantity => memory_override.nil? ? machine_conf.memory[:quantity] : memory_override[1],
+      :units => machine_conf.memory[:units]
+    }
+  end
+
+  def self.convert_instance_storage(profile, context)
+    machine_conf = CIMI::Model::MachineConfiguration.find(profile.name, context)
+    storage_override = profile.overrides.find { |p, v| p == :storage }
+    [
+      { :capacity => {
+          :quantity => storage_override.nil? ? machine_conf.disks.first[:capacity][:quantity] : storage_override[1],
+          :units => machine_conf.disks.first[:capacity][:units]
+        }
+      }
+    ]
+  end
+
+  def self.convert_instance_addresses(instance)
+    (instance.public_addresses + instance.private_addresses).collect do |address|
+      {
+        :hostname => address.is_hostname? ? address : nil,
+        :mac_address => address.is_mac? ? address : nil,
+        :state => 'Active',
+        :protocol => 'IPv4',
+        :address => address.is_ipv4? ? address : nil,
+        :allocation => 'Static'
+      }
+    end
+  end
+
+  def self.convert_instance_actions(instance, context)
+    instance.actions.collect do |action|
+      action = :destroy if action == :delete # In CIMI destroy operation become delete
+      action = :restart if action == :reboot  # In CIMI reboot operation become restart
+      { :href => context.send(:"#{action}_machine_url", instance.id), :rel => "http://www.dmtf.org/cimi/action/#{action}" }
+    end
+  end
+
+  def self.convert_storage_volumes(instance, context)
+    instance.storage_volumes ||= [] #deal with nilpointers
+    instance.storage_volumes.map{|vol| {:href=>context.volume_url(vol.keys.first),
+                                       :attachment_point=>vol.values.first} }
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_admin.rb b/server/lib/cimi/models/machine_admin.rb
new file mode 100644
index 0000000..fed7c80
--- /dev/null
+++ b/server/lib/cimi/models/machine_admin.rb
@@ -0,0 +1,59 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineAdmin < CIMI::Model::Base
+
+  text :username
+  text :password
+  text :key
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id == :all
+      keys = context.driver.keys(context.credentials)
+      keys.map { |key| from_key(key, context) }
+    else
+      key = context.driver.key(context.credentials, :id => id)
+      from_key(key, context)
+    end
+  end
+
+  def self.create_from_xml(body, context)
+    machine_admin = MachineAdmin.from_xml(body)
+    key = context.driver.create_key(context.credentials, :key_name => machine_admin.name)
+    from_key(key, context)
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_key(context.credentials, :id => id)
+  end
+
+  private
+
+  def self.from_key(key, context)
+    self.new(
+      :name => key.id,
+      :username => key.username,
+      :password => key.is_password? ? key.password : key.fingerprint,
+      :key => key.is_key? ? key.pem_rsa_key : nil,
+      :id => context.machine_admin_url(key.id),
+      :created => Time.now
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_admin_collection.rb b/server/lib/cimi/models/machine_admin_collection.rb
new file mode 100644
index 0000000..08c1559
--- /dev/null
+++ b/server/lib/cimi/models/machine_admin_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineAdminCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_admin
+
+  array :machine_admins do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_admins_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineAdminCollection",
+      :machine_admins => CIMI::Model::MachineAdmin.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_collection.rb b/server/lib/cimi/models/machine_collection.rb
new file mode 100644
index 0000000..9154aa9
--- /dev/null
+++ b/server/lib/cimi/models/machine_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine
+
+  array :machines do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machines_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineCollection",
+      :machines => CIMI::Model::Machine.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_configuration.rb b/server/lib/cimi/models/machine_configuration.rb
new file mode 100644
index 0000000..f9d98f2
--- /dev/null
+++ b/server/lib/cimi/models/machine_configuration.rb
@@ -0,0 +1,70 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineConfiguration < CIMI::Model::Base
+
+  struct :memory do
+    scalar :quantity
+    scalar :units
+  end
+
+  text :cpu
+
+  array :disks do
+    struct :capacity do
+      scalar :quantity
+      scalar :units
+    end
+    scalar :format
+    scalar :attachment_point
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    profiles = []
+    if id == :all
+      profiles = context.driver.hardware_profiles(context.credentials)
+      profiles.map { |profile| from_hardware_profile(profile, context) }.compact
+    else
+      profile = context.driver.hardware_profile(context.credentials, id)
+      from_hardware_profile(profile, context)
+    end
+  end
+
+  private
+
+  def self.from_hardware_profile(profile, context)
+    # We accept just profiles with all properties set
+    return unless profile.memory or profile.cpu or profile.storage
+    memory = profile.memory.value || profile.memory.default
+    cpu = profile.cpu.value || profile.cpu.default
+    storage = profile.storage.value || profile.storage.default
+    machine_hash = {
+      :name => profile.name,
+      :description => "Machine Configuration with #{memory} #{profile.memory.unit} "+
+        "of memory and #{cpu} CPU",
+      :cpu => cpu,
+      :created => Time.now.to_s,  # FIXME: DC hardware_profile has no mention about created_at
+      :memory => { :quantity => profile.memory.value || profile.memory.default, :units => profile.memory.unit },
+      :disks => [ { :capacity => { :quantity => profile.storage.value || profile.storage.default, :units => profile.storage.unit } } ],
+      :id => context.machine_configuration_url(profile.name)
+    }
+    self.new(machine_hash)
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_configuration_collection.rb b/server/lib/cimi/models/machine_configuration_collection.rb
new file mode 100644
index 0000000..6d7ebad
--- /dev/null
+++ b/server/lib/cimi/models/machine_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineConfigurationCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_configuration
+
+  array :machine_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineConfigurationCollection",
+      :machine_configurations => CIMI::Model::MachineConfiguration.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_image.rb b/server/lib/cimi/models/machine_image.rb
new file mode 100644
index 0000000..7389475
--- /dev/null
+++ b/server/lib/cimi/models/machine_image.rb
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineImage < CIMI::Model::Base
+
+  href :image_location
+  text :image_data
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    images = []
+    if id == :all
+      images = context.driver.images(context.credentials)
+      images.map { |image| from_image(image, context) }
+    else
+      image = context.driver.image(context.credentials, :id => id)
+      from_image(image, context)
+    end
+  end
+
+  def self.from_image(image, context)
+    self.new(
+      :name => image.id,
+      :id => context.machine_image_url(image.id),
+      :description => image.description,
+      :created => Time.now.to_s,
+      :image_location => { :href => "#{context.driver.name}://#{image.id}" } # FIXME
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_image_collection.rb b/server/lib/cimi/models/machine_image_collection.rb
new file mode 100644
index 0000000..70bdc7b
--- /dev/null
+++ b/server/lib/cimi/models/machine_image_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineImageCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_image
+
+  array :machine_images do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_images_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineImageCollection",
+      :machine_images => CIMI::Model::MachineImage.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/machine_template.rb b/server/lib/cimi/models/machine_template.rb
new file mode 100644
index 0000000..8a88052
--- /dev/null
+++ b/server/lib/cimi/models/machine_template.rb
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineTemplate < CIMI::Model::Base
+
+  href :machine_config
+  href :machine_image
+  href :machine_admin
+
+  array :volumes do
+    scalar :href
+    scalar :protocol
+    scalar :attachment_point
+  end
+
+  array :volume_templates do
+    scalar :href, :attachment_point, :protocol
+  end
+
+  array :network_interfaces do
+    href :vsp
+    text :hostname, :mac_address, :state, :protocol, :allocation
+    text :address, :default_gateway, :dns, :max_transmission_unit
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+end
diff --git a/server/lib/cimi/models/machine_template_collection.rb b/server/lib/cimi/models/machine_template_collection.rb
new file mode 100644
index 0000000..d2a3f23
--- /dev/null
+++ b/server/lib/cimi/models/machine_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::MachineTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :machine_template
+
+  array :machine_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.machine_template_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} MachineTemplateCollection",
+      :machine_templates => CIMI::Model::MachineTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/network.rb b/server/lib/cimi/models/network.rb
new file mode 100644
index 0000000..3d9c7ed
--- /dev/null
+++ b/server/lib/cimi/models/network.rb
@@ -0,0 +1,109 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Network < CIMI::Model::Base
+
+  text :state
+
+  text :access
+
+  text :bandwidth_limit
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  href :routing_group
+
+  href :event_log
+
+  array :meters do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    networks=[]
+    if id==:all
+      networks = context.driver.networks(context.credentials, {:env=>context})
+    else
+      networks = context.driver.networks(context.credentials, {:id=>id, :env=>context})
+    end
+    networks
+  end
+
+  def self.create(request_body, context, type)
+    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false,"NormaliseSpace"=>2}) : JSON.parse(request_body)
+    if input["networkTemplate"]["href"] #template by reference
+      network_config, routing_group = get_by_reference(input, context)
+    else
+      if input["networkTemplate"]["networkConfig"]["href"] # configuration by reference
+        network_config = CIMI::Model::NetworkConfiguration.find(context.href_id(input["networkTemplate"]["networkConfig"]["href"],
+                                                                                :network_configurations), context)
+      else #configuration by value
+        network_config = get_by_value(request_body, type)
+      end
+      routing_group = CIMI::Model::RoutingGroup.find(context.href_id(input["networkTemplate"]["routingGroup"]["href"],
+                                                                     :routing_groups), context)
+    end
+    params = {:network_config => network_config, :routing_group => routing_group, :name=>input["name"],
+              :description=>input["description"], :env=>context}
+    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
+    context.driver.create_network(context.credentials, params)
+  end
+
+  def self.delete!(id, context)
+    context.driver.delete_network(context.credentials, id)
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_network", context.credentials, self.name)
+        block.callback :success
+      else
+        raise "Operation #{action.name} failed to execute on the Network #{self.name} "
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+  private
+
+  def self.get_by_reference(input, context)
+    network_template = CIMI::Model::NetworkTemplate.find(context.href_id(input["networkTemplate"]["href"], :network_templates), context)
+    network_config = CIMI::Model::NetworkConfiguration.find(context.href_id(network_template.network_config.href, :network_configurations), context)
+    routing_group = CIMI::Model::RoutingGroup.find(context.href_id(network_template.routing_group.href, :routing_groups), context)
+    return network_config, routing_group
+  end
+
+  def self.get_by_value(request_body, type)
+    if type == :xml
+      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
+      network_config = CIMI::Model::NetworkConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["networkTemplate"][0]["networkConfig"][0]))
+    else
+     json = JSON.parse(request_body)
+      network_config = CIMI::Model::NetworkConfiguration.from_json(JSON.generate(json["networkTemplate"]["networkConfig"]))
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/network_collection.rb b/server/lib/cimi/models/network_collection.rb
new file mode 100644
index 0000000..d76a3dd
--- /dev/null
+++ b/server/lib/cimi/models/network_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkCollection < CIMI::Model::Base
+
+  act_as_root_entity :network
+
+  array :networks do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.networks_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} NetworkCollection",
+      :networks => CIMI::Model::Network.all(context).map { |c| { :href => c.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/network_configuration.rb b/server/lib/cimi/models/network_configuration.rb
new file mode 100644
index 0000000..1b04548
--- /dev/null
+++ b/server/lib/cimi/models/network_configuration.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkConfiguration < CIMI::Model::Base
+
+  text :access
+
+  text :bandwidth_limit
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    network_configs = []
+    if id==:all
+      network_configs = context.driver.network_configurations(context.credentials, {:env=>context})
+    else
+      network_configs = context.driver.network_configurations(context.credentials, {:env=>context, :id=>id})
+    end
+    network_configs
+  end
+
+  def self.create_from_xml(request_body, context)
+  end
+
+  def self.create_from_json(request_body, context)
+  end
+end
diff --git a/server/lib/cimi/models/network_configuration_collection.rb b/server/lib/cimi/models/network_configuration_collection.rb
new file mode 100644
index 0000000..fc14592
--- /dev/null
+++ b/server/lib/cimi/models/network_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkConfigurationCollection < CIMI::Model::Base
+
+  act_as_root_entity :network_configuration
+
+  array :network_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.network_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} NetworkConfigurationCollection",
+      :network_configurations => CIMI::Model::NetworkConfiguration.all(context).map { |c| { :href => c.id } }
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/network_template.rb b/server/lib/cimi/models/network_template.rb
new file mode 100644
index 0000000..ce3b990
--- /dev/null
+++ b/server/lib/cimi/models/network_template.rb
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::NetworkTemplate < CIMI::Model::Base
+
+  href :network_config
+
+  href :routing_group
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    network_templates = []
+    if id==:all
+      network_templates = context.driver.network_templates(context.credentials, {:env=>context})
+    else
+      network_templates = context.driver.network_templates(context.credentials, {:env=>context, :id=>id})
+    end
+    network_templates
+  end
+
+end
diff --git a/server/lib/cimi/models/network_template_collection.rb b/server/lib/cimi/models/network_template_collection.rb
new file mode 100644
index 0000000..b2ac537
--- /dev/null
+++ b/server/lib/cimi/models/network_template_collection.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class CIMI::Model::NetworkTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :network_template
+
+  array :network_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.network_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} NetworkTemplateCollection",
+      :network_templates => CIMI::Model::NetworkTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group.rb b/server/lib/cimi/models/routing_group.rb
new file mode 100644
index 0000000..d26f4d7
--- /dev/null
+++ b/server/lib/cimi/models/routing_group.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::RoutingGroup < CIMI::Model::Base
+
+  array :networks do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.routing_groups(context.credentials, {:env=>context})
+    else
+      context.driver.routing_groups(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group_collection.rb b/server/lib/cimi/models/routing_group_collection.rb
new file mode 100644
index 0000000..285e164
--- /dev/null
+++ b/server/lib/cimi/models/routing_group_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::RoutingGroupCollection < CIMI::Model::Base
+
+  act_as_root_entity :routing_group
+
+  array :routing_groups do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.routing_groups_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} RoutingGroupCollection",
+      :routing_groups => CIMI::Model::RoutingGroup.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group_template.rb b/server/lib/cimi/models/routing_group_template.rb
new file mode 100644
index 0000000..204a353
--- /dev/null
+++ b/server/lib/cimi/models/routing_group_template.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::RoutingGroupTemplate < CIMI::Model::Base
+
+  array :networks do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.routing_group_templates(context.credentials, {:env=>context})
+    else
+      context.driver.routing_group_templates(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/routing_group_template_collection.rb b/server/lib/cimi/models/routing_group_template_collection.rb
new file mode 100644
index 0000000..61a4a68
--- /dev/null
+++ b/server/lib/cimi/models/routing_group_template_collection.rb
@@ -0,0 +1,35 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+class CIMI::Model::RoutingGroupTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :routing_group_template
+
+  array :routing_group_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.routing_group_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} RoutingGroupTemplateCollection",
+      :routing_group_templates => CIMI::Model::RoutingGroupTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb
new file mode 100644
index 0000000..f301b69
--- /dev/null
+++ b/server/lib/cimi/models/schema.rb
@@ -0,0 +1,277 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+# The smarts of converting from XML and JSON into internal objects
+class CIMI::Model::Schema
+
+  #
+  # Attributes describe how we extract values from XML/JSON
+  #
+  class Attribute
+    attr_reader :name, :xml_name, :json_name
+
+    def initialize(name, opts = {})
+      @name = name
+      @xml_name = (opts[:xml_name] || name).to_s.camelize(true)
+      @json_name = (opts[:json_name] || name).to_s.camelize(true)
+    end
+
+    def from_xml(xml, model)
+      model[@name] = xml[@xml_name].first if xml.has_key?(@xml_name)
+    end
+
+    def from_json(json, model)
+      model[@name] = json[@json_name]
+    end
+
+    def to_xml(model, xml)
+      xml[@xml_name] = [model[@name]] if model[@name]
+    end
+
+    def to_json(model, json)
+      json[@json_name] = model[@name] if model and model[@name]
+    end
+  end
+
+  class Scalar < Attribute
+    def initialize(name, opts)
+      @text = opts[:text]
+      if ! [nil, :nested, :direct].include?(@text)
+        raise "text option for scalar must be :nested or :direct"
+      end
+      super(name, opts)
+    end
+
+    def text?; @text; end
+
+    def nested_text?; @text == :nested; end
+
+    def from_xml(xml, model)
+      case @text
+        when :nested then model[@name] = xml[@xml_name].first["content"] if xml[@xml_name]
+        when :direct then model[@name] = xml["content"]
+        else model[@name] = xml[@xml_name]
+      end
+    end
+
+    def to_xml(model, xml)
+      return unless model
+      return unless model[@name]
+      case @text
+        when :nested then xml[@xml_name] = [{ "content" => model[@name] }]
+        when :direct then xml["content"] = model[@name]
+        else xml[@xml_name] = model[@name]
+      end
+    end
+  end
+
+  class Struct < Attribute
+    def initialize(name, opts, &block)
+      content = opts[:content]
+      super(name, opts)
+      @schema = CIMI::Model::Schema.new
+      @schema.instance_eval(&block) if block_given?
+      @schema.scalar(content, :text => :direct) if content
+    end
+
+    def from_xml(xml, model)
+      xml = xml.has_key?(xml_name) ? xml[xml_name].first : {}
+      model[name] = convert_from_xml(xml)
+    end
+
+    def from_json(json, model)
+      json = json.has_key?(json_name) ? json[json_name] : {}
+      model[name] = convert_from_json(json)
+    end
+
+    def to_xml(model, xml)
+      conv = convert_to_xml(model[name])
+      xml[xml_name] = [conv] unless conv.empty?
+    end
+
+    def to_json(model, json)
+      conv = convert_to_json(model[name])
+      json[json_name] = conv unless conv.empty?
+    end
+
+    def convert_from_xml(xml)
+      sub = struct.new
+      @schema.from_xml(xml, sub)
+      sub
+    end
+
+    def convert_from_json(json)
+      sub = struct.new
+      @schema.from_json(json, sub)
+      sub
+    end
+
+    def convert_to_xml(model)
+      xml = {}
+      @schema.to_xml(model, xml)
+      xml
+    end
+
+    def convert_to_json(model)
+      json = {}
+      @schema.to_json(model, json)
+      json
+    end
+
+    private
+    def struct
+      cname = "CIMI_#{json_name.upcase_first}"
+      if ::Struct.const_defined?(cname)
+        ::Struct.const_get(cname)
+      else
+        ::Struct.new("CIMI_#{json_name.upcase_first}",
+                     *@schema.attribute_names)
+      end
+    end
+  end
+
+  class Array < Attribute
+    # For an array :things, we collect all <thing/> elements (XmlSimple
+    # actually does the collecting)
+    def initialize(name, opts = {}, &block)
+      opts[:xml_name] = name.to_s.singularize unless opts[:xml_name]
+      super(name, opts)
+      @struct = Struct.new(name, opts, &block)
+    end
+
+    def from_xml(xml, model)
+      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
+    end
+
+    def from_json(json, model)
+      model[name] = (json[json_name] || []).map { |elt| @struct.convert_from_json(elt) }
+    end
+
+    def to_xml(model, xml)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
+      xml[xml_name] = ary unless ary.empty?
+    end
+
+    def to_json(model, json)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
+      json[json_name] = ary unless ary.empty?
+    end
+  end
+
+  class Hash < Attribute
+
+    def initialize(name, opts = {}, &block)
+      opts[:json_name] = name.to_s.pluralize unless opts[:json_name]
+      super(name, opts)
+      @struct = Struct.new(name, opts, &block)
+    end
+
+    def from_xml(xml, model)
+      model[name] = (xml[xml_name] || []).map { |elt| @struct.convert_from_xml(elt) }
+    end
+
+    def from_json(json, model)
+      model[name] = (json[json_name] || {}).inject([]) do |result,item|
+        result << @struct.convert_from_json({ 'name' => item[0], 'value' => item[1] })
+      end
+    end
+
+    def to_xml(model, xml)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_xml(elt) }
+      xml[xml_name] = ary unless ary.empty?
+    end
+
+    def to_json(model, json)
+      ary = (model[name] || []).map { |elt| @struct.convert_to_json(elt) }
+      json[json_name] = ary.inject({}) { |result, item| result[item['name']] = item['value']; result } unless ary.empty?
+    end
+  end
+
+  #
+  # The actual Schema class
+  #
+  def initialize
+    @attributes = []
+  end
+
+  def from_xml(xml, model = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.from_xml(xml, model) }
+    model
+  end
+
+  def from_json(json, model = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.from_json(json, model) }
+    model
+  end
+
+  def to_xml(model, xml = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.to_xml(model, xml) }
+    xml
+  end
+
+  def to_json(model, json = {})
+    @attributes.freeze
+    @attributes.each { |attr| attr.to_json(model, json) }
+    json
+  end
+
+  def attribute_names
+    @attributes.map { |a| a.name }
+  end
+
+  #
+  # The DSL
+  #
+  # Requires that the class into which this is included has a
+  # +add_attributes!+ method
+  module DSL
+    def href(*args)
+      args.each { |arg| struct(arg) { scalar :href } }
+    end
+
+    def text(*args)
+      args.expand_opts!(:text => :nested)
+      scalar(*args)
+    end
+
+    def scalar(*args)
+      add_attributes!(args, Scalar)
+    end
+
+    def array(name, opts={}, &block)
+      add_attributes!([name, opts], Array, &block)
+    end
+
+    def struct(name, opts={}, &block)
+      add_attributes!([name, opts], Struct, &block)
+    end
+
+    def hash(name, opts={}, &block)
+      add_attributes!([name, opts], Hash, &block)
+    end
+  end
+
+  include DSL
+
+  def add_attributes!(args, attr_klass, &block)
+    raise "The schema has already been used to convert objects" if @attributes.frozen?
+    opts = args.extract_opts!
+    args.each { |arg| @attributes << attr_klass.new(arg, opts, &block) }
+  end
+end
diff --git a/server/lib/cimi/models/volume.rb b/server/lib/cimi/models/volume.rb
new file mode 100644
index 0000000..9c106e2
--- /dev/null
+++ b/server/lib/cimi/models/volume.rb
@@ -0,0 +1,103 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::Volume < CIMI::Model::Base
+
+  struct :capacity do
+    scalar :quantity
+    scalar :units
+  end
+  text :bootable
+  text :supports_snapshots
+  array :snapshots do
+    scalar :ref
+  end
+  text :guest_interface
+  array :meters do
+    scalar :ref
+  end
+  href :eventlog
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    volumes = []
+    opts = ( id == :all ) ? {} : { :id => id }
+    volumes = context.driver.storage_volumes(context.credentials, opts)
+    volumes.collect!{ |volume| from_storage_volume(volume, context) }
+    return volumes.first unless volumes.length > 1
+    return volumes
+  end
+
+  def self.all(context); find(:all, context); end
+
+  def self.create_from_json(json_in, context)
+    json = JSON.parse(json_in)
+    volume_config_id = json["volumeTemplate"]["volumeConfig"]["href"].split("/").last
+    volume_image_id = (json["volumeTemplate"].has_key?("volumeImage") ?
+                json["volumeTemplate"]["volumeImage"]["href"].split("/").last  : nil)
+    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
+  end
+
+  def self.create_from_xml(xml_in, context)
+    xml = XmlSimple.xml_in(xml_in)
+    volume_config_id = xml["volumeTemplate"][0]["volumeConfig"][0]["href"].split("/").last
+    volume_image_id = (xml["volumeTemplate"][0].has_key?("volumeImage") ?
+             xml["volumeTemplate"][0]["volumeImage"][0]["href"].split("/").last  : nil)
+    create_volume({:volume_config_id=>volume_config_id, :volume_image_id=>volume_image_id}, context)
+  end
+
+  def self.delete!(id, context)
+    context.driver.destroy_storage_volume(context.credentials, {:id=>id} )
+  end
+
+  def self.find_to_attach_from_json(json_in, context)
+    json = JSON.parse(json_in)
+    volumes = json["volumes"].map{|v| {:volume=>self.find(v["volume"]["href"].split("/volumes/").last, context),
+                                       :attachment_point=>v["attachmentPoint"]  }}
+  end
+
+  def self.find_to_attach_from_xml(xml_in, context)
+    xml = XmlSimple.xml_in(xml_in)
+    volumes = xml["volume"].map{|v| {:volume => self.find(v["href"].split("/volumes/").last, context),
+                                      :attachment_point=>v["attachmentPoint"] }}
+  end
+
+  private
+
+  def self.create_volume(params, context)
+    volume_config = CIMI::Model::VolumeConfiguration.find(params[:volume_config_id], context)
+    opts = {:capacity=>volume_config.capacity[:quantity], :snapshot_id=>params[:volume_image_id] }
+    storage_volume = self.driver.create_storage_volume(context.credentials, opts)
+    from_storage_volume(storage_volume, context)
+  end
+
+  def self.from_storage_volume(volume, context)
+    self.new( { :name => volume.id,
+                :description => volume.id,
+                :created => volume.created,
+                :id => context.volume_url(volume.id),
+                :capacity => { :quantity=>volume.capacity, :units=>"gibibyte"  }, #FIXME... units will vary
+                :bootable => "false", #fixme ... will vary... ec2 doesn't expose this
+                :supports_snapshots => "true", #fixme, will vary (true for ec2)
+                :snapshots => [], #fixme...
+                :guest_interface => "",
+                :eventlog => {:href=> "http://eventlogs"},#FIXME
+                :meters => []
+            } )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_collection.rb b/server/lib/cimi/models/volume_collection.rb
new file mode 100644
index 0000000..1f4152e
--- /dev/null
+++ b/server/lib/cimi/models/volume_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume
+
+  array :volumes do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volumes_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeCollection",
+      :volumes => CIMI::Model::Volume.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_configuration.rb b/server/lib/cimi/models/volume_configuration.rb
new file mode 100644
index 0000000..75b37ea
--- /dev/null
+++ b/server/lib/cimi/models/volume_configuration.rb
@@ -0,0 +1,60 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeConfiguration < CIMI::Model::Base
+
+  text :format
+  struct :capacity do
+    scalar :quantity
+    scalar :units
+  end
+  text :supports_snapshots
+  text :guest_interface
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    volume_configs = []
+    if id == :all
+      #ec2 ebs volumes can 1gb..1tb
+      (1..1000).each do |size|
+        volume_configs << create(size, context)
+      end
+    else
+      volume_configs << create(id, context)
+      return volume_configs.first
+    end
+    return volume_configs
+  end
+
+
+  def self.all(context); find(:all, context); end
+
+  private
+
+  def self.create(size, context)
+    self.new( {
+                :id => context.volume_configuration_url(size),
+                :name => size,
+                :description => "volume configuration with #{size} GiB",
+                :created => Time.now.to_s,
+                :capacity => {:quantity=>size, :units=>"gibibytes"},
+                :supports_snapshots => "true"
+                # FIXME :guest_interface => "NFS"
+            } )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_configuration_collection.rb b/server/lib/cimi/models/volume_configuration_collection.rb
new file mode 100644
index 0000000..2120ae6
--- /dev/null
+++ b/server/lib/cimi/models/volume_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeConfigurationCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume_configuration
+
+  array :volume_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volume_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeConfigurationCollection",
+      :volume_configurations => CIMI::Model::VolumeConfiguration.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_image.rb b/server/lib/cimi/models/volume_image.rb
new file mode 100644
index 0000000..03cc7fd
--- /dev/null
+++ b/server/lib/cimi/models/volume_image.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeImage < CIMI::Model::Base
+
+  href :image_location
+  text :image_data
+  text :bootable
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    storage_snapshots = []
+    opts = ( id==:all  ) ? {}  : { :id=>id }
+    storage_snapshots = self.driver.storage_snapshots(context.credentials, opts)
+    storage_snapshots.collect!{ |snapshot| from_storage_snapshot(snapshot, context) }
+    return storage_snapshots.first unless storage_snapshots.length > 1
+    return storage_snapshots
+  end
+
+  def self.all(context); find(:all, context); end
+
+  private
+
+  def self.from_storage_snapshot(snapshot, context)
+    self.new( {
+               :name => snapshot.id,
+               :description => snapshot.id,
+               :created => snapshot.created,
+               :id => context.volume_image_url(snapshot.id),
+               :image_location => {:href=>context.volume_url(snapshot.storage_volume_id)},
+               :bootable => "false"  #FIXME
+            } )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_image_collection.rb b/server/lib/cimi/models/volume_image_collection.rb
new file mode 100644
index 0000000..f3da877
--- /dev/null
+++ b/server/lib/cimi/models/volume_image_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeImageCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume_image
+
+  array :volume_images do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volume_images_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeImageCollection",
+      :volume_images => CIMI::Model::VolumeImage.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/volume_template.rb b/server/lib/cimi/models/volume_template.rb
new file mode 100644
index 0000000..b9c82db
--- /dev/null
+++ b/server/lib/cimi/models/volume_template.rb
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeTemplate < CIMI::Model::Base
+
+  href :volume_config
+  href :volume_image
+  array :operations do
+    scalar :rel, :href
+  end
+end
diff --git a/server/lib/cimi/models/volume_template_collection.rb b/server/lib/cimi/models/volume_template_collection.rb
new file mode 100644
index 0000000..f53547c
--- /dev/null
+++ b/server/lib/cimi/models/volume_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VolumeTemplateCollection < CIMI::Model::Base
+
+  act_as_root_entity :volume_template
+
+  array :volume_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.volume_template_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VolumeTemplateCollection",
+      :volume_templates => CIMI::Model::VolumeTemplate.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp.rb b/server/lib/cimi/models/vsp.rb
new file mode 100644
index 0000000..b8b27f5
--- /dev/null
+++ b/server/lib/cimi/models/vsp.rb
@@ -0,0 +1,102 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSP < CIMI::Model::Base
+
+  text :state
+
+  href :network
+
+  text :bandwidth_reservation
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  href :event_log
+
+  array :meters do
+    scalar :href
+  end
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.vsps(context.credentials, {:env=>context})
+    else
+      context.driver.vsps(context.credentials, {:id=>id, :env=>context})
+    end
+  end
+
+  def self.create(request_body, context, type)
+    input = (type == :xml)? XmlSimple.xml_in(request_body, {"ForceArray"=>false, "NormaliseSpace"=>2}) : JSON.parse(request_body)
+    if input["vspTemplate"]["href"] #template by reference
+      vsp_config, network = get_by_reference(input, context)
+    else
+      if input["vspTemplate"]["vspConfig"]["href"] # configuration by reference
+        vsp_config = CIMI::Model::VSPConfiguration.find(context.href_id(input["vspTemplate"]["vspConfig"]["href"],:vsp_configurations), context)
+      else #configuration by value
+        vsp_config = get_by_value(request_body, type)
+      end
+      network = CIMI::Model::Network.find(context.href_id(input["vspTemplate"]["network"]["href"], :networks), context)
+    end
+    params = {:vsp_config => vsp_config, :network => network, :name=>input["name"], :description=>input["description"], :env=>context}
+    raise CIMI::Model::BadRequest.new("Bad request - missing required parameters. Client sent: #{request_body} which produced #{params.inspect}")  if params.has_value?(nil)
+    context.driver.create_vsp(context.credentials, params)
+  end
+
+  def self.delete!(id, context)
+    context.driver.delete_vsp(context.credentials, id)
+  end
+
+  def perform(action, context, &block)
+    begin
+      if context.driver.send(:"#{action.name}_vsp", context.credentials, self.name)
+        block.callback :success
+      else
+        raise "Operation #{action.name} failed to execute on the VSP #{self.name} "
+      end
+    rescue => e
+      block.callback :failure, e.message
+    end
+  end
+
+
+  private
+
+  def self.get_by_reference(input, context)
+    vsp_template = CIMI::Model::VSPTemplate.find(context.href_id(input["vspTemplate"]["href"], :vsp_templates), context)
+    vsp_config = CIMI::Model::VSPConfiguration.find(context.href_id(vsp_template.vsp_config.href, :vsp_configurations), context)
+    network = CIMI::Model::Network.find(context.href_id(vsp_template.network.href, :networks), context)
+    return vsp_config, network
+  end
+
+  def self.get_by_value(request_body, type)
+    if type == :xml
+      xml_arrays = XmlSimple.xml_in(request_body, {"NormaliseSpace"=>2})
+      vsp_config = CIMI::Model::VSPConfiguration.from_xml(XmlSimple.xml_out(xml_arrays["vspTemplate"][0]["vspConfig"][0]))
+    else
+     json = JSON.parse(request_body)
+      vsp_config = CIMI::Model::VSPConfiguration.from_json(JSON.generate(json["vspTemplate"]["vspConfig"]))
+    end
+  end
+end
diff --git a/server/lib/cimi/models/vsp_collection.rb b/server/lib/cimi/models/vsp_collection.rb
new file mode 100644
index 0000000..fc72024
--- /dev/null
+++ b/server/lib/cimi/models/vsp_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPCollection < CIMI::Model::Base
+
+  CIMI::Model.register_as_root_entity! "VSPs"
+
+  array :vsps do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.vsps_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VSPCollection",
+      :vsps => CIMI::Model::VSP.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_configuration.rb b/server/lib/cimi/models/vsp_configuration.rb
new file mode 100644
index 0000000..c9a9bf3
--- /dev/null
+++ b/server/lib/cimi/models/vsp_configuration.rb
@@ -0,0 +1,40 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPConfiguration < CIMI::Model::Base
+
+  text :bandwidth_reservation
+
+  text :traffic_priority
+
+  text :max_traffic_delay
+
+  text :max_traffic_loss
+
+  text :max_traffic_jitter
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.vsp_configurations(context.credentials, {:env=>context})
+    else
+      context.driver.vsp_configurations(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_configuration_collection.rb b/server/lib/cimi/models/vsp_configuration_collection.rb
new file mode 100644
index 0000000..d4927e7
--- /dev/null
+++ b/server/lib/cimi/models/vsp_configuration_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPConfigurationCollection < CIMI::Model::Base
+
+  CIMI::Model.register_as_root_entity! "VSPConfigurations"
+
+  array :vsp_configurations do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.vsp_configurations_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VSPConfigurationCollection",
+      :vsp_configurations => CIMI::Model::VSPConfiguration.all_uri(context)
+    )
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_template.rb b/server/lib/cimi/models/vsp_template.rb
new file mode 100644
index 0000000..f1b8078
--- /dev/null
+++ b/server/lib/cimi/models/vsp_template.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPTemplate < CIMI::Model::Base
+
+  href :network
+
+  href :vsp_config
+
+  array :operations do
+    scalar :rel, :href
+  end
+
+  def self.find(id, context)
+    if id==:all
+      context.driver.vsp_templates(context.credentials, {:env=>context})
+    else
+      context.driver.vsp_templates(context.credentials, {:env=>context, :id=>id})
+    end
+  end
+
+end
diff --git a/server/lib/cimi/models/vsp_template_collection.rb b/server/lib/cimi/models/vsp_template_collection.rb
new file mode 100644
index 0000000..61d5311
--- /dev/null
+++ b/server/lib/cimi/models/vsp_template_collection.rb
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+class CIMI::Model::VSPTemplateCollection < CIMI::Model::Base
+
+  CIMI::Model.register_as_root_entity! "VSPTemplates"
+
+  array :vsp_templates do
+    scalar :href
+  end
+
+  def self.default(context)
+    self.new(
+      :id => context.vsp_templates_url,
+      :name => 'default',
+      :created => Time.now,
+      :description => "#{context.driver.name.capitalize} VSPTemplateCollection",
+      :vsp_templates => CIMI::Model::VSPTemplate.all_uri(context)
+    )
+  end
+
+end
-- 
1.7.10


[PATCH core 30/32] Core: Switch to use driver.class.has_feature? instead of driver_has_feature?

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/collections/instances.rb |    3 +++
 server/views/instances/new.html.haml           |   12 ++++++------
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/server/lib/deltacloud/collections/instances.rb b/server/lib/deltacloud/collections/instances.rb
index 5202149..0da94f2 100644
--- a/server/lib/deltacloud/collections/instances.rb
+++ b/server/lib/deltacloud/collections/instances.rb
@@ -27,6 +27,9 @@ module Deltacloud::Collections
       @hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
       @realms = [Realm.new(:id => params[:realm_id])] if params[:realm_id]
       @realms ||= driver.realms(credentials)
+      if driver.class.has_feature? :instances, :authentication_key
+        @keys = driver.keys(credentials)
+      end
     end
 
     collection :instances do
diff --git a/server/views/instances/new.html.haml b/server/views/instances/new.html.haml
index 2347022..5ca775c 100644
--- a/server/views/instances/new.html.haml
+++ b/server/views/instances/new.html.haml
@@ -21,7 +21,7 @@
   %form{ :action => instances_url, :method => :post, :class => :new_instance, :'data-ajax' => 'false'}
     %input{ :name => :image_id, :type => :hidden, :value => @instance.image_id }/
 
-    - if driver_has_feature?(:user_name)
+    - if driver.class.has_feature?(:instances, :user_name)
       %div{ 'data-role' => :fieldcontain }
         %label{ :for => :name} Instance name:
         %input{ :type => :text, :id => :name, :name => :name, :value => '' }
@@ -29,19 +29,19 @@
     %div{ 'data-role' => :collapsible, 'data-collapsed' => "true"}
       %h3 Additional parameters
 
-      - if driver_has_feature?(:user_data)
+      - if driver.class.has_feature?(:instances, :user_data)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :user_data} Base64 encoded user-data:
           %textarea{ :id => :user_data, :name => :user_data, :value => '' }
           %br/
           %a{ :href => "", :onclick => 'encodeb64();', :'data-ajax' => 'false'} Encode data
 
-      - if driver_has_feature?(:instance_count)
+      - if driver.class.has_feature?(:instances, :instance_count)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :instance_count} # of instances to be launched:
           %input{ :type => :text, :id => :instance_count, :name => :instance_count, :value => '1' }
 
-      - if driver_has_feature?(:authentication_key)
+      - if driver.class.has_feature?(:instances, :authentication_key)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :keyname, :class => 'ui-input-text'} Instance SSH key:
           %select{:name => 'keyname', :'data-native-menu' => "true" }
@@ -49,7 +49,7 @@
             - @keys.each do |key|
               %option{ :value => key.id } #{key.id}
 
-      - if driver_has_feature?(:register_to_load_balancer)
+      - if driver.class.has_feature?(:instances, :register_to_load_balancer)
         %div{ 'data-role' => :fieldcontain }
           %label{ :for => :load_balancer_id, :class => 'ui-input-text'} Register to loadbalancer:
           %select{:name => 'load_balancer_id', :'data-native-menu' => "true" }
@@ -57,7 +57,7 @@
             - @load_balancers.each do |load_balancer|
               %option{:value => load_balancer.id} #{load_balancer.id}
 
-      - if driver_has_feature?(:firewalls)
+      - if driver.class.has_feature?(:instances, :firewalls)
         %div{ 'data-role' => :fieldcontain }
           %fieldset{ :'data-role' => 'controlgroup'}
             %legend Register to firewall:
-- 
1.7.10


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

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


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

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


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

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

Hi again :-)

Since it's pretty hard to track the 'modular' tree (it's ~40 patches now),
I created a remote GIT repo here: https://github.com/mifo/deltacloud

To use it just go to the deltacloud git directory and type:

$ cd core
$ git remote add modular git://github.com/mifo/deltacloud.git
$ git checkout -b modular modular/deltacloud_modular

Then you should have the 'modular' branch that should allow clean rebase
against master branch. I'll add new patches and fixed to this repo and once
it will be stable enough and everyone will be happy with this we can merge
them very easely.

Cheers,
  -- Michal

PS: If you want to get rw access to the github repo, just ping me on IRC.

> On 05/02/12, Michal Fojtik wrote:
> 
> I updated it once again. I tried to fix all 1.8 compatibility issues and
> the test suite works fine under 1.8:
> 
> $ gem install minitest
> $ rake test:api
> 
> Please note, that you *need* to uninstall the 'deltacloud-core' gem if you
> already have it installed, otherwise you get something like 'Uninitialized
> constant Deltacloud'. I'll try to figure out how to prevent this error
> together with switching all our testing suites to be Base compatible.
> 


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

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

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

I updated it once again. I tried to fix all 1.8 compatibility issues and
the test suite works fine under 1.8:

$ gem install minitest
$ rake test:api

Please note, that you *need* to uninstall the 'deltacloud-core' gem if you
already have it installed, otherwise you get something like 'Uninitialized
constant Deltacloud'. I'll try to figure out how to prevent this error
together with switching all our testing suites to be Base compatible.

  -- Michal

> On 05/02/12, Michal Fojtik wrote:
> 
> I've fixed the blobs/buckets stuff. An updated patch (is just one file,
> that you need to apply on master branch) is here:
> 
> http://omicron.mifo.sk/deltacloud_modular.patch.gz
> 
>   -- michal
> 
> 
> > On 05/01/12, marios@redhat.com wrote:
> > > very high lever/initial comments to get started (its a huge change!):
> > > 
> > > * what kind of testing has been done? like e.g. all the unit tests?
> > 
> > So far I just have copied over my 'minitest' tests under
> > 'server/tests/drivers/api'. Those should run fine against this patchset.
> > 
> > The other test suites must be updated to work with Sinatra::Base. I'm
> > currently working on this update.
> > 
> > > * very nice - tidying up of each collections to separate file
> > > * nice autoloading of models
> > > * where are blob streaming hacks? (used to be in blob_stream.rb) ("Core:
> > > Removed deprecated helpers")
> > 
> > Sorry for this. Seems like I removed more that I should remove. I copied
> > the file back and load it in lib/deltacloud/helpers.
> > 
> > > * I tried cd /server; rake rabbit:routes but got "rake aborted!
> > > uninitialized constant Deltacloud" - pebkac?
> > 
> > Right. This is caused by 'deltacloud-core' gem. If this gem is installed,
> > it try to load it and not the one in current directory. I'll try to figure
> > out how to avoid that. A simple workaround would be to uninstall
> > deltacloud-core gem.
> > 
> > > * couldn't start the server. I installed sinatra-rabbit:
> > 
> > Same issue as above ^^.
> > 
> > > [marios@name server]$ irb -rubygems
> > > irb(main):001:0> require 'sinatra/rabbit'
> > > NameError: uninitialized constant Deltacloud
> > >         from
> > > /usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/deltacloud/validation.rb:17
> > >         from
> > 
> > OK so I should focus on validation file, thanks :-)
> > 
> > Thanks a ton for looking on this patch. I found some 19 compat issues in
> > routing and I will try to fix it today and sent an updated patchset.
> > 
> >   -- Michal
> > 
> > > On 17/04/12 16:39, mfojtik@redhat.com wrote:
> > > > From: Michal Fojtik <mf...@redhat.com>
> > > > 
> > > > 
> > > > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > > > ---
> > > >  server/deltacloud-core.gemspec |    1 +
> > > >  1 file changed, 1 insertion(+)
> > > > 
> > > > diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> > > > index 55aa182..54d88cc 100644
> > > > --- a/server/deltacloud-core.gemspec
> > > > +++ b/server/deltacloud-core.gemspec
> > > > @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
> > > >    s.add_dependency('rake', '>= 0.8.7')
> > > >    s.add_dependency('haml', '>= 2.2.17')
> > > >    s.add_dependency('sinatra', '>= 0.9.4')
> > > > +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
> > > >    s.add_dependency('rack', '>= 1.0.0')
> > > >    s.add_dependency('rack-accept')
> > > >    s.add_dependency('json', '>= 1.1.9')
> > > 
> > 
> > -- 
> > Michal Fojtik
> > Sr. Software Engineer, Deltacloud API (http://deltacloud.org)
> 
> -- 
> Michal Fojtik
> Sr. Software Engineer, Deltacloud API (http://deltacloud.org)

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

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

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

I've fixed the blobs/buckets stuff. An updated patch (is just one file,
that you need to apply on master branch) is here:

http://omicron.mifo.sk/deltacloud_modular.patch.gz

  -- michal


> On 05/01/12, marios@redhat.com wrote:
> > very high lever/initial comments to get started (its a huge change!):
> > 
> > * what kind of testing has been done? like e.g. all the unit tests?
> 
> So far I just have copied over my 'minitest' tests under
> 'server/tests/drivers/api'. Those should run fine against this patchset.
> 
> The other test suites must be updated to work with Sinatra::Base. I'm
> currently working on this update.
> 
> > * very nice - tidying up of each collections to separate file
> > * nice autoloading of models
> > * where are blob streaming hacks? (used to be in blob_stream.rb) ("Core:
> > Removed deprecated helpers")
> 
> Sorry for this. Seems like I removed more that I should remove. I copied
> the file back and load it in lib/deltacloud/helpers.
> 
> > * I tried cd /server; rake rabbit:routes but got "rake aborted!
> > uninitialized constant Deltacloud" - pebkac?
> 
> Right. This is caused by 'deltacloud-core' gem. If this gem is installed,
> it try to load it and not the one in current directory. I'll try to figure
> out how to avoid that. A simple workaround would be to uninstall
> deltacloud-core gem.
> 
> > * couldn't start the server. I installed sinatra-rabbit:
> 
> Same issue as above ^^.
> 
> > [marios@name server]$ irb -rubygems
> > irb(main):001:0> require 'sinatra/rabbit'
> > NameError: uninitialized constant Deltacloud
> >         from
> > /usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/deltacloud/validation.rb:17
> >         from
> 
> OK so I should focus on validation file, thanks :-)
> 
> Thanks a ton for looking on this patch. I found some 19 compat issues in
> routing and I will try to fix it today and sent an updated patchset.
> 
>   -- Michal
> 
> > On 17/04/12 16:39, mfojtik@redhat.com wrote:
> > > From: Michal Fojtik <mf...@redhat.com>
> > > 
> > > 
> > > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > > ---
> > >  server/deltacloud-core.gemspec |    1 +
> > >  1 file changed, 1 insertion(+)
> > > 
> > > diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> > > index 55aa182..54d88cc 100644
> > > --- a/server/deltacloud-core.gemspec
> > > +++ b/server/deltacloud-core.gemspec
> > > @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
> > >    s.add_dependency('rake', '>= 0.8.7')
> > >    s.add_dependency('haml', '>= 2.2.17')
> > >    s.add_dependency('sinatra', '>= 0.9.4')
> > > +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
> > >    s.add_dependency('rack', '>= 1.0.0')
> > >    s.add_dependency('rack-accept')
> > >    s.add_dependency('json', '>= 1.1.9')
> > 
> 
> -- 
> Michal Fojtik
> Sr. Software Engineer, Deltacloud API (http://deltacloud.org)

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

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

Posted by Michal Fojtik <mf...@redhat.com>.
On 05/01/12, marios@redhat.com wrote:
> very high lever/initial comments to get started (its a huge change!):
> 
> * what kind of testing has been done? like e.g. all the unit tests?

So far I just have copied over my 'minitest' tests under
'server/tests/drivers/api'. Those should run fine against this patchset.

The other test suites must be updated to work with Sinatra::Base. I'm
currently working on this update.

> * very nice - tidying up of each collections to separate file
> * nice autoloading of models
> * where are blob streaming hacks? (used to be in blob_stream.rb) ("Core:
> Removed deprecated helpers")

Sorry for this. Seems like I removed more that I should remove. I copied
the file back and load it in lib/deltacloud/helpers.

> * I tried cd /server; rake rabbit:routes but got "rake aborted!
> uninitialized constant Deltacloud" - pebkac?

Right. This is caused by 'deltacloud-core' gem. If this gem is installed,
it try to load it and not the one in current directory. I'll try to figure
out how to avoid that. A simple workaround would be to uninstall
deltacloud-core gem.

> * couldn't start the server. I installed sinatra-rabbit:

Same issue as above ^^.

> [marios@name server]$ irb -rubygems
> irb(main):001:0> require 'sinatra/rabbit'
> NameError: uninitialized constant Deltacloud
>         from
> /usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/deltacloud/validation.rb:17
>         from

OK so I should focus on validation file, thanks :-)

Thanks a ton for looking on this patch. I found some 19 compat issues in
routing and I will try to fix it today and sent an updated patchset.

  -- Michal

> On 17/04/12 16:39, mfojtik@redhat.com wrote:
> > From: Michal Fojtik <mf...@redhat.com>
> > 
> > 
> > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > ---
> >  server/deltacloud-core.gemspec |    1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> > index 55aa182..54d88cc 100644
> > --- a/server/deltacloud-core.gemspec
> > +++ b/server/deltacloud-core.gemspec
> > @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
> >    s.add_dependency('rake', '>= 0.8.7')
> >    s.add_dependency('haml', '>= 2.2.17')
> >    s.add_dependency('sinatra', '>= 0.9.4')
> > +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
> >    s.add_dependency('rack', '>= 1.0.0')
> >    s.add_dependency('rack-accept')
> >    s.add_dependency('json', '>= 1.1.9')
> 

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

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

Posted by "marios@redhat.com" <ma...@redhat.com>.
very high lever/initial comments to get started (its a huge change!):

* what kind of testing has been done? like e.g. all the unit tests?
* very nice - tidying up of each collections to separate file
* nice autoloading of models
* where are blob streaming hacks? (used to be in blob_stream.rb) ("Core:
Removed deprecated helpers")
* I tried cd /server; rake rabbit:routes but got "rake aborted!
uninitialized constant Deltacloud" - pebkac?
* couldn't start the server. I installed sinatra-rabbit:

[marios@name server]$ ./bin/deltacloudd -i mock
Starting Deltacloud API :: mock :: http://localhost:3001/api

/usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/deltacloud/validation.rb:17:
uninitialized constant Deltacloud (NameError)
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:53:in
`gem_original_require'
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:53:in `require'
        from
/usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/sinatra/rabbit.rb:19
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:57:in
`gem_original_require'
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:57:in `require'
        from
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/lib/deltacloud/server.rb:7
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in
`gem_original_require'
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
        from
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/config.ru:35
        from
/usr/lib/ruby/gems/1.8/gems/rack-1.4.1/lib/rack/builder.rb:51:in
`instance_eval'
        from
/usr/lib/ruby/gems/1.8/gems/rack-1.4.1/lib/rack/builder.rb:51:in
`initialize'
        from
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/config.ru:1:in
`new'
        from
/home/marios/Documents/WORK/NewEclipsey/DCore/deltacloud_git_repo/deltacloud/server/config.ru:1

following the trace a bit I did:

[marios@name server]$ irb -rubygems
irb(main):001:0> require 'sinatra/rabbit'
NameError: uninitialized constant Deltacloud
        from
/usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/deltacloud/validation.rb:17
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:53:in
`gem_original_require'
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:53:in `require'
        from
/usr/lib/ruby/gems/1.8/gems/deltacloud-core-0.4.1/lib/sinatra/rabbit.rb:19
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:57:in
`gem_original_require'
        from
/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:57:in `require'
        from (irb):1

is this more pebkac?

marios






On 17/04/12 16:39, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/deltacloud-core.gemspec |    1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> index 55aa182..54d88cc 100644
> --- a/server/deltacloud-core.gemspec
> +++ b/server/deltacloud-core.gemspec
> @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
>    s.add_dependency('rake', '>= 0.8.7')
>    s.add_dependency('haml', '>= 2.2.17')
>    s.add_dependency('sinatra', '>= 0.9.4')
> +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
>    s.add_dependency('rack', '>= 1.0.0')
>    s.add_dependency('rack-accept')
>    s.add_dependency('json', '>= 1.1.9')


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

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


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

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


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

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


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

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


[PATCH core 07/32] Core: Removed ApplicationHelper from the instance model and added name method to key model

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/models/instance.rb |    2 --
 server/lib/deltacloud/models/key.rb      |    4 ++++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index c6835a9..c2cc0e3 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -16,8 +16,6 @@
 
 class Instance < BaseModel
 
-  include ApplicationHelper
-
   attr_accessor :owner_id
   attr_accessor :image_id
   attr_accessor :name
diff --git a/server/lib/deltacloud/models/key.rb b/server/lib/deltacloud/models/key.rb
index 86a6283..64c4cc7 100644
--- a/server/lib/deltacloud/models/key.rb
+++ b/server/lib/deltacloud/models/key.rb
@@ -23,6 +23,10 @@ class Key < BaseModel
   attr_accessor :pem_rsa_key
   attr_accessor :state
 
+  def name
+    @name || @id
+  end
+
   def is_password?
     true if @credential_type.eql?(:password)
   end
-- 
1.7.10


[PATCH core 12/32] Core: Removed validation helper, validation is now done by Rabbit

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/validation.rb |  100 -----------------------------------
 1 file changed, 100 deletions(-)
 delete mode 100644 server/lib/deltacloud/validation.rb

diff --git a/server/lib/deltacloud/validation.rb b/server/lib/deltacloud/validation.rb
deleted file mode 100644
index 3d29225..0000000
--- a/server/lib/deltacloud/validation.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud::Validation
-
-  class Param
-    attr_reader :name, :klass, :type, :options, :description
-
-    def initialize(args)
-      @name = args[0]
-      @klass = args[1] || :string
-      @type = args[2] || :optional
-      @options = args[3] || []
-      @description = args[4] || ''
-    end
-
-    def required?
-      type.eql?(:required)
-    end
-
-    def optional?
-      type.eql?(:optional)
-    end
-
-    def valid_value?(value)
-      true if (options.kind_of?(Range) or options.kind_of?(Array)) and options.include?(value)
-      true if options.kind_of?(String) and not options.empty?
-    end
-
-    def valid_hwp_value?(profile, value)
-      profile.property(@name.to_s.gsub(/^hwp_/, '')).valid?(value)
-    end
-
-    def hwp_property?
-      true if name.to_s =~ /^hwp_(cpu|memory|storage|architecture)/
-    end
-  end
-
-  def param(*args)
-    raise "Duplicate param #{args[0]} #{params.inspect} #{self.class.name}" if params[args[0]]
-    p = Param.new(args)
-    params[p.name] = p
-  end
-
-  def params
-    @params ||= {}
-    @params
-  end
-
-  # Add the parameters in hash +new+ to already existing parameters. If
-  # +new+ contains a parameter with an already existing name, the old
-  # definition is clobbered.
-  def add_params(new)
-    # We do not check for duplication on purpose: multiple calls
-    # to add_params should be cumulative
-    new.each { |p|  @params[p.name] = p }
-  end
-
-  def each_param(&block)
-    params.each_value { |p| yield p }
-  end
-
-  def validate(current_driver, all_params, values, credentials)
-    all_params.each do |key, p|
-      if p.required? and not values[p.name]
-        raise validation_exception "Required parameter #{p.name} not found"
-      end
-      next unless values[p.name]
-      if p.hwp_property?
-        profile = current_driver.hardware_profile(credentials, values['hwp_id'])
-        raise validation_exception("Unknown hardware profile selected #{values['hwp_id']}") unless profile
-        unless p.valid_hwp_value?(profile, values[p.name])
-          raise validation_exception("Hardware profile property #{p.name} has invalid value #{values[p.name]}")
-        end
-      else
-        if not p.options.empty? and p.valid_value?(values[p.name])
-          raise validation_exception("Parameter #{p.name} has value #{values[p.name]} which is not in #{p.options.join(", ")}")
-        end
-      end
-    end
-  end
-
-  def validation_exception(message)
-    Deltacloud::ExceptionHandler::ValidationFailure.new(StandardError.new(message))
-  end
-
-end
-- 
1.7.10


Re: [PATCH core 23/32] Core: Storage volumes should always show the :name attribute

Posted by Michal Fojtik <mf...@redhat.com>.
On 04/30/12, Koper, Dies wrote:
> Hi Michal,
> 
> > +++ b/server/views/storage_volumes/show.html.haml
> ...
> > +    %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id
> 
> What I don't understand about this patch is that the subject says that
> the :name attribute should be shown (I believe it is currently not in
> the GUI and that is inconvenient for FGCP as the name is much more
> meaningful than the id) but you're not adding any lines with :name in
> them?

Hi,

What does this patch do is to have the '<name>' attribute always visible,
even if it's not set. In that case we fallback to the 'id' and will display
the content of 'id' in 'name'.

Thing is that clients would expect to have 'id' and 'name' always available
in the XML/JSON.

  -- Michal

> 
> Regards,
> Dies Koper
> 
> 
> > -----Original Message-----
> > From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> > Sent: Tuesday, 17 April 2012 11:40 PM
> > To: dev@deltacloud.apache.org
> > Subject: [PATCH core 23/32] Core: Storage volumes should always show
> > the :name attribute
> > 
> > From: Michal Fojtik <mf...@redhat.com>
> > 
> > 
> > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > ---
> >  server/views/storage_volumes/show.html.haml |    1 +
> >  server/views/storage_volumes/show.xml.haml  |    5 ++---
> >  2 files changed, 3 insertions(+), 3 deletions(-)
> > 
> > diff --git a/server/views/storage_volumes/show.html.haml
> > b/server/views/storage_volumes/show.html.haml
> > index aabdd85..1c1f458 100644
> > --- a/server/views/storage_volumes/show.html.haml
> > +++ b/server/views/storage_volumes/show.html.haml
> > @@ -4,6 +4,7 @@
> >  %div{ :'data-role' => :content, :'data-theme' => 'c'}
> >    %ul{ :'data-role' => :listview , :'data-inset' => :true,
> :'data-divider-theme'
> > => 'd'}
> >      %li{ :'data-role' => 'list-divider'} Name
> > +    %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id
> >      %li
> >        %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id
> >      %li{ :'data-role' => 'list-divider'} Created
> > diff --git a/server/views/storage_volumes/show.xml.haml
> > b/server/views/storage_volumes/show.xml.haml
> > index 440609b..f9f5f25 100644
> > --- a/server/views/storage_volumes/show.xml.haml
> > +++ b/server/views/storage_volumes/show.xml.haml
> > @@ -9,9 +9,8 @@
> >    - if @storage_volume.kind
> >      %kind<
> >        = @storage_volume.kind
> > -  - if @storage_volume.name
> > -    %name<
> > -      = @storage_volume.name
> > +  %name<
> > +    = @storage_volume.name || @storage_volume.id
> >    - if @storage_volume.device
> >      %device<
> >        = @storage_volume.device
> > --
> > 1.7.10
> > 
> 
> 

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

RE: [PATCH core 23/32] Core: Storage volumes should always show the :name attribute

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

> +++ b/server/views/storage_volumes/show.html.haml
...
> +    %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id

What I don't understand about this patch is that the subject says that
the :name attribute should be shown (I believe it is currently not in
the GUI and that is inconvenient for FGCP as the name is much more
meaningful than the id) but you're not adding any lines with :name in
them?

Regards,
Dies Koper


> -----Original Message-----
> From: mfojtik@redhat.com [mailto:mfojtik@redhat.com]
> Sent: Tuesday, 17 April 2012 11:40 PM
> To: dev@deltacloud.apache.org
> Subject: [PATCH core 23/32] Core: Storage volumes should always show
> the :name attribute
> 
> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/views/storage_volumes/show.html.haml |    1 +
>  server/views/storage_volumes/show.xml.haml  |    5 ++---
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/server/views/storage_volumes/show.html.haml
> b/server/views/storage_volumes/show.html.haml
> index aabdd85..1c1f458 100644
> --- a/server/views/storage_volumes/show.html.haml
> +++ b/server/views/storage_volumes/show.html.haml
> @@ -4,6 +4,7 @@
>  %div{ :'data-role' => :content, :'data-theme' => 'c'}
>    %ul{ :'data-role' => :listview , :'data-inset' => :true,
:'data-divider-theme'
> => 'd'}
>      %li{ :'data-role' => 'list-divider'} Name
> +    %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id
>      %li
>        %p{ :'data-role' => 'fieldcontain'}=@storage_volume.id
>      %li{ :'data-role' => 'list-divider'} Created
> diff --git a/server/views/storage_volumes/show.xml.haml
> b/server/views/storage_volumes/show.xml.haml
> index 440609b..f9f5f25 100644
> --- a/server/views/storage_volumes/show.xml.haml
> +++ b/server/views/storage_volumes/show.xml.haml
> @@ -9,9 +9,8 @@
>    - if @storage_volume.kind
>      %kind<
>        = @storage_volume.kind
> -  - if @storage_volume.name
> -    %name<
> -      = @storage_volume.name
> +  %name<
> +    = @storage_volume.name || @storage_volume.id
>    - if @storage_volume.device
>      %device<
>        = @storage_volume.device
> --
> 1.7.10
> 



[PATCH core 23/32] Core: Storage volumes should always show the :name attribute

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


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

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


[PATCH core 18/32] Core: Added the :name property to Deltacloud Key model

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


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

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


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

Posted by Michal Fojtik <mf...@redhat.com>.
On 04/26/12, Michal Fojtik wrote:
> On 04/26/12, Michal Fojtik wrote:
> > On 04/17/12, mfojtik@redhat.com wrote:
> > 
> > For those, who don't want to download this patch serie one-by-one,
> > I created a tarball: http://omicron.mifo.sk/tmp/dc_patch.tar.gz
> 
> Sorry for wrong link: http://omicron.mifo.sk/dc_patch.tar.gz

Since I just pushed the 'metrics' collection, an updated patches can be
found here: http://omicron.mifo.sk/dc_modular_30Apr.tar.gz

 -- michal

> 
> > 
> >   -- michal
> > 
> > > From: Michal Fojtik <mf...@redhat.com>
> > > 
> > > 
> > > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > > ---
> > >  server/deltacloud-core.gemspec |    1 +
> > >  1 file changed, 1 insertion(+)
> > > 
> > > diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> > > index 55aa182..54d88cc 100644
> > > --- a/server/deltacloud-core.gemspec
> > > +++ b/server/deltacloud-core.gemspec
> > > @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
> > >    s.add_dependency('rake', '>= 0.8.7')
> > >    s.add_dependency('haml', '>= 2.2.17')
> > >    s.add_dependency('sinatra', '>= 0.9.4')
> > > +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
> > >    s.add_dependency('rack', '>= 1.0.0')
> > >    s.add_dependency('rack-accept')
> > >    s.add_dependency('json', '>= 1.1.9')
> > > -- 
> > > 1.7.10
> > > 
> 
> -- 
> Michal Fojtik
> Sr. Software Engineer, Deltacloud API (http://deltacloud.org)

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

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

Posted by Michal Fojtik <mf...@redhat.com>.
On 04/26/12, Michal Fojtik wrote:
> On 04/17/12, mfojtik@redhat.com wrote:
> 
> For those, who don't want to download this patch serie one-by-one,
> I created a tarball: http://omicron.mifo.sk/tmp/dc_patch.tar.gz

Sorry for wrong link: http://omicron.mifo.sk/dc_patch.tar.gz

> 
>   -- michal
> 
> > From: Michal Fojtik <mf...@redhat.com>
> > 
> > 
> > Signed-off-by: Michal fojtik <mf...@redhat.com>
> > ---
> >  server/deltacloud-core.gemspec |    1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> > index 55aa182..54d88cc 100644
> > --- a/server/deltacloud-core.gemspec
> > +++ b/server/deltacloud-core.gemspec
> > @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
> >    s.add_dependency('rake', '>= 0.8.7')
> >    s.add_dependency('haml', '>= 2.2.17')
> >    s.add_dependency('sinatra', '>= 0.9.4')
> > +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
> >    s.add_dependency('rack', '>= 1.0.0')
> >    s.add_dependency('rack-accept')
> >    s.add_dependency('json', '>= 1.1.9')
> > -- 
> > 1.7.10
> > 

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

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

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

For those, who don't want to download this patch serie one-by-one,
I created a tarball: http://omicron.mifo.sk/tmp/dc_patch.tar.gz

  -- michal

> From: Michal Fojtik <mf...@redhat.com>
> 
> 
> Signed-off-by: Michal fojtik <mf...@redhat.com>
> ---
>  server/deltacloud-core.gemspec |    1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
> index 55aa182..54d88cc 100644
> --- a/server/deltacloud-core.gemspec
> +++ b/server/deltacloud-core.gemspec
> @@ -68,6 +68,7 @@ Gem::Specification.new do |s|
>    s.add_dependency('rake', '>= 0.8.7')
>    s.add_dependency('haml', '>= 2.2.17')
>    s.add_dependency('sinatra', '>= 0.9.4')
> +  s.add_dependency('sinatra-rabbit', '>= 1.0.5')
>    s.add_dependency('rack', '>= 1.0.0')
>    s.add_dependency('rack-accept')
>    s.add_dependency('json', '>= 1.1.9')
> -- 
> 1.7.10
> 

[PATCH core 24/32] Core: Removed autoregistration of the CIMI helper

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


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

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


[PATCH core 26/32] CIMI: Splitted CIMI server to separate collections like in Deltacloud

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/cimi/collections.rb                     |   58 ++
 server/lib/cimi/collections/address_templates.rb   |   49 +
 server/lib/cimi/collections/addresses.rb           |   74 ++
 server/lib/cimi/collections/cloud_entry_point.rb   |   32 +
 server/lib/cimi/collections/entity_metadata.rb     |   48 +
 server/lib/cimi/collections/machine_admins.rb      |   74 ++
 .../lib/cimi/collections/machine_configurations.rb |   49 +
 server/lib/cimi/collections/machine_images.rb      |   50 +
 server/lib/cimi/collections/machines.rb            |  157 ++++
 .../lib/cimi/collections/network_configurations.rb |   47 +
 server/lib/cimi/collections/network_templates.rb   |   48 +
 server/lib/cimi/collections/networks.rb            |  125 +++
 .../cimi/collections/routing_group_templates.rb    |   47 +
 server/lib/cimi/collections/routing_groups.rb      |   48 +
 .../lib/cimi/collections/volume_configurations.rb  |   48 +
 server/lib/cimi/collections/volume_images.rb       |   50 +
 server/lib/cimi/collections/volumes.rb             |   80 ++
 server/lib/cimi/collections/vsp_configurations.rb  |   48 +
 server/lib/cimi/collections/vsp_templates.rb       |   50 +
 server/lib/cimi/collections/vsps.rb                |  108 +++
 server/lib/cimi/helpers.rb                         |  104 +++
 server/lib/cimi/model.rb                           |   67 --
 server/lib/cimi/models.rb                          |   75 ++
 server/lib/cimi/server.rb                          |  959 +-------------------
 24 files changed, 1499 insertions(+), 996 deletions(-)
 create mode 100644 server/lib/cimi/collections.rb
 create mode 100644 server/lib/cimi/collections/address_templates.rb
 create mode 100644 server/lib/cimi/collections/addresses.rb
 create mode 100644 server/lib/cimi/collections/cloud_entry_point.rb
 create mode 100644 server/lib/cimi/collections/entity_metadata.rb
 create mode 100644 server/lib/cimi/collections/machine_admins.rb
 create mode 100644 server/lib/cimi/collections/machine_configurations.rb
 create mode 100644 server/lib/cimi/collections/machine_images.rb
 create mode 100644 server/lib/cimi/collections/machines.rb
 create mode 100644 server/lib/cimi/collections/network_configurations.rb
 create mode 100644 server/lib/cimi/collections/network_templates.rb
 create mode 100644 server/lib/cimi/collections/networks.rb
 create mode 100644 server/lib/cimi/collections/routing_group_templates.rb
 create mode 100644 server/lib/cimi/collections/routing_groups.rb
 create mode 100644 server/lib/cimi/collections/volume_configurations.rb
 create mode 100644 server/lib/cimi/collections/volume_images.rb
 create mode 100644 server/lib/cimi/collections/volumes.rb
 create mode 100644 server/lib/cimi/collections/vsp_configurations.rb
 create mode 100644 server/lib/cimi/collections/vsp_templates.rb
 create mode 100644 server/lib/cimi/collections/vsps.rb
 create mode 100644 server/lib/cimi/helpers.rb
 delete mode 100644 server/lib/cimi/model.rb
 create mode 100644 server/lib/cimi/models.rb

diff --git a/server/lib/cimi/collections.rb b/server/lib/cimi/collections.rb
new file mode 100644
index 0000000..b675fc4
--- /dev/null
+++ b/server/lib/cimi/collections.rb
@@ -0,0 +1,58 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI
+
+  def self.collection_names
+    @collections.map { |c| c.collection_name }
+  end
+
+  def self.collections
+    @collections ||= []
+  end
+
+  module Collections
+
+    def self.collection(name)
+      CIMI.collections.find { |c| c.collection_name == name }
+    end
+
+    def self.cimi_modules
+      @cimi_modules ||= []
+    end
+
+    Dir[File.join(File::dirname(__FILE__), "collections", "*.rb")].each do |collection|
+      require collection
+      base_collection_name = File.basename(collection).gsub('.rb', '')
+      cimi_module_class = CIMI::Collections.const_get(base_collection_name.camelize)
+      cimi_modules << cimi_module_class
+      unless cimi_module_class.collections.nil?
+        cimi_module_class.collections.each do |c|
+          CIMI.collections << c
+        end
+      else
+        warn "WARNING: File %s placed in collections directory but does not have any collections defined" % base_collection_name
+      end
+    end
+
+    def self.included(klass)
+      klass.class_eval do
+        CIMI::Collections.cimi_modules.each { |c| use c }
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/address_templates.rb b/server/lib/cimi/collections/address_templates.rb
new file mode 100644
index 0000000..db59507
--- /dev/null
+++ b/server/lib/cimi/collections/address_templates.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class AddressTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :address_templates do
+
+      operation :index do
+        description 'List all AddressTemplates in the AddressTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          address_templates = AddressTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {address_templates.to_xml}
+            format.json {address_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific AddressTemplate'
+        control do
+          address_template = CIMI::Model::AddressTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {address_template.to_xml}
+            format.json {address_template.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/addresses.rb b/server/lib/cimi/collections/addresses.rb
new file mode 100644
index 0000000..96871c1
--- /dev/null
+++ b/server/lib/cimi/collections/addresses.rb
@@ -0,0 +1,74 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Addresses < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :addresses do
+
+      description 'An Address represents an IP address, and its associated metdata, for a particular Network.'
+
+      operation :index do
+        description 'List all Addresses in the AddressCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          addresses = AddressCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {addresses.to_xml}
+            format.json {addresses.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific Address'
+        control do
+          address = CIMI::Model::Address.find(params[:id], self)
+          respond_to do |format|
+            format.xml {address.to_xml}
+            format.json {address.to_json}
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Address"
+        control do
+          if request.content_type.end_with?("json")
+            address = CIMI::Model::Address.create(request.body.read, self, :json)
+          else
+            address = CIMI::Model::Address.create(request.body.read, self, :xml)
+          end
+          respond_to do |format|
+            format.xml { address.to_xml }
+            format.json { address.to_json }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified Address"
+        param :id, :string, :required
+        control do
+          CIMI::Model::Address.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/cloud_entry_point.rb b/server/lib/cimi/collections/cloud_entry_point.rb
new file mode 100644
index 0000000..79454f3
--- /dev/null
+++ b/server/lib/cimi/collections/cloud_entry_point.rb
@@ -0,0 +1,32 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class CloudEntryPoint < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection  :cloudEntryPoint do
+      description 'Cloud entry point'
+      operation :index do
+        description "list all resources of the cloud"
+        control do
+          redirect API_ROOT_URL
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/entity_metadata.rb b/server/lib/cimi/collections/entity_metadata.rb
new file mode 100644
index 0000000..84e1fec
--- /dev/null
+++ b/server/lib/cimi/collections/entity_metadata.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class EntityMetadata < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :entity_metadata do
+
+      operation :index do
+        description "List all entity metadata defined for this provider"
+        control do
+          entity_metadata = CIMI::Model::EntityMetadataCollection.default(self)
+          respond_to do |format|
+            format.xml{entity_metadata.to_xml}
+            format.json{entity_metadata.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description "Get the entity metadata for a specific collection"
+        control do
+          entity_metadata = EntityMetadata.find(params[:id], self)
+          respond_to do |format|
+            format.xml{entity_metadata.to_xml}
+            format.json{entity_metadata.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machine_admins.rb b/server/lib/cimi/collections/machine_admins.rb
new file mode 100644
index 0000000..c413cc9
--- /dev/null
+++ b/server/lib/cimi/collections/machine_admins.rb
@@ -0,0 +1,74 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class MachineAdmins < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machine_admins do
+      description 'Machine Admin entity'
+
+      operation :index do
+        description "List all machine admins"
+        param :CIMISelect,  :string,  :optional
+        control do
+          machine_admins = MachineAdminCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machine_admins.to_xml }
+            format.json { machine_admins.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific machine admin"
+        control do
+          machine_admin = MachineAdmin.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine_admin.to_xml }
+            format.json { machine_admin.to_json }
+          end
+        end
+      end
+
+      operation :create do
+        description "Show specific machine admin"
+        control do
+          if request.content_type.end_with?("+json")
+            new_admin = MachineAdmin.create_from_json(request.body.read, self)
+          else
+            new_admin = MachineAdmin.create_from_xml(request.body.read, self)
+          end
+          status 201 # Created
+          respond_to do |format|
+            format.json { new_admin.to_json }
+            format.xml { new_admin.to_xml }
+          end
+        end
+      end
+
+      operation :delete do
+        description "Delete specified MachineAdmin entity"
+        control do
+          MachineAdmin.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machine_configurations.rb b/server/lib/cimi/collections/machine_configurations.rb
new file mode 100644
index 0000000..5b09e6a
--- /dev/null
+++ b/server/lib/cimi/collections/machine_configurations.rb
@@ -0,0 +1,49 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class MachineConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machine_configurations do
+      description 'List all machine configurations'
+
+      operation :index do
+        param :CIMISelect,  :string,  :optional
+        description "List all machine configurations"
+        control do
+          machine_configs = MachineConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machine_configs.to_xml }
+            format.json { machine_configs.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        control do
+          machine_conf = MachineConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine_conf.to_xml }
+            format.json { machine_conf.to_json }
+          end
+        end
+
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machine_images.rb b/server/lib/cimi/collections/machine_images.rb
new file mode 100644
index 0000000..1296279
--- /dev/null
+++ b/server/lib/cimi/collections/machine_images.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class MachineImages < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machine_images do
+      description 'List all machine images'
+
+      operation :index do
+        description "List all machine configurations"
+        param :CIMISelect,  :string,  :optional
+        control do
+          machine_images = MachineImageCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machine_images.to_xml }
+            format.json { machine_images.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific machine image."
+        control do
+          machine_image = MachineImage.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine_image.to_xml }
+            format.json { machine_image.to_json }
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/machines.rb b/server/lib/cimi/collections/machines.rb
new file mode 100644
index 0000000..0abf63a
--- /dev/null
+++ b/server/lib/cimi/collections/machines.rb
@@ -0,0 +1,157 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Machines < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :machines do
+      description 'List all machine'
+
+      operation :index do
+        param :CIMISelect,  :string,  :optional
+        description "List all machines"
+        control do
+          machines = MachineCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { machines.to_xml }
+            format.json { machines.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          respond_to do |format|
+            format.xml { machine.to_xml }
+            format.json { machine.to_json }
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Machine entity."
+        control do
+          if request.content_type.end_with?("+json")
+            new_machine = Machine.create_from_json(request.body.read, self)
+          else
+            new_machine = Machine.create_from_xml(request.body.read, self)
+          end
+          status 201 # Created
+          respond_to do |format|
+            format.json { new_machine.to_json }
+            format.xml { new_machine.to_xml }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified machine."
+        param :id,          :string,    :required
+        control do
+          Machine.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :stop do
+        description "Stop specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          if request.content_type.end_with?("+json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          machine.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      operation :restart do
+        description "Start specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          if request.content_type.end_with?("+json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          machine.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      operation :start do
+        description "Start specific machine."
+        control do
+          machine = Machine.find(params[:id], self)
+          if request.content_type.end_with?("+json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          machine.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      #NOTE: The routes for attach/detach used here are NOT as specified by CIMI
+      #will likely move later. CIMI specifies PUT of the whole Machine description
+      #with inclusion/ommission of the volumes you want [att|det]ached
+      action :attach_volume, :http_method => :put do
+        description "Attach CIMI Volume(s) to a machine."
+        control do
+          if request.content_type.end_with?("+json")
+            volumes_to_attach = Volume.find_to_attach_from_json(request.body.read, self)
+          else
+            volumes_to_attach = Volume.find_to_attach_from_xml(request.body.read, self)
+          end
+          machine = Machine.attach_volumes(volumes_to_attach, self)
+          respond_to do |format|
+            format.json{ machine.to_json}
+            format.xml{machine.to_xml}
+          end
+        end
+      end
+
+      action :detach_volume, :http_method => :put do
+        description "Detach CIMI Volume(s) from a machine."
+        control do
+          if request.content_type.end_with?("+json")
+            volumes_to_detach = Volume.find_to_attach_from_json(request.body.read, self)
+          else
+            volumes_to_detach = Volume.find_to_attach_from_xml(request.body.read, self)
+          end
+          machine = Machine.detach_volumes(volumes_to_detach, self)
+          respond_to do |format|
+            format.json{ machine.to_json}
+            format.xml{machine.to_xml}
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/network_configurations.rb b/server/lib/cimi/collections/network_configurations.rb
new file mode 100644
index 0000000..02452a8
--- /dev/null
+++ b/server/lib/cimi/collections/network_configurations.rb
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class NetworkConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :network_configurations do
+
+      operation :index do
+        description 'List all NetworkConfigurations'
+        param :CIMISelect, :string, :optional
+        control do
+          network_configurations = NetworkConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { network_configurations.to_xml  }
+            format.json { network_configurations.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific NetworkConfiguration'
+        control do
+          network_config = NetworkConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml { network_config.to_xml }
+            format.json { network_config.to_json }
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/network_templates.rb b/server/lib/cimi/collections/network_templates.rb
new file mode 100644
index 0000000..0ff82b2
--- /dev/null
+++ b/server/lib/cimi/collections/network_templates.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class NetworkTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :network_templates do
+
+      operation :index do
+        description 'List all Network Templates in the NetworkTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          network_templates = NetworkTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {network_templates.to_xml}
+            format.json {network_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific Network Template'
+        control do
+          network_template = NetworkTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {network_template.to_xml}
+            format.json {network_template.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/networks.rb b/server/lib/cimi/collections/networks.rb
new file mode 100644
index 0000000..0aa21e8
--- /dev/null
+++ b/server/lib/cimi/collections/networks.rb
@@ -0,0 +1,125 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Networks < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :networks do
+      description 'A Network represents an abstraction of a layer 2 broadcast domain'
+
+      operation :index do
+        description "List all Networks"
+        param :CIMISelect,  :string,  :optional
+        control do
+          networks = NetworkCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { networks.to_xml }
+            format.json { networks.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show a specific Network"
+        control do
+          network = Network.find(params[:id], self)
+          respond_to do |format|
+            format.xml { network.to_xml }
+            format.json { network.to_json }
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Network"
+        control do
+          if request.content_type.end_with?("json")
+            network = Network.create(request.body.read, self, :json)
+          else
+            network = Network.create(request.body.read, self, :xml)
+          end
+          respond_to do |format|
+            format.xml { network.to_xml}
+            format.json { network.to_json }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified Network"
+        param :id, :string, :required
+        control do
+          Network.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :start do
+        description "Start specific network."
+        control do
+          network = Network.find(params[:id], self)
+          report_error(404) unless network
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          network.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :stop do
+        description "Stop specific network."
+        control do
+          network = Network.find(params[:id], self)
+          report_error(404) unless network
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          network.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :suspend do
+        description "Suspend specific network."
+        control do
+          network = Network.find(params[:id], self)
+          report_error(404) unless network
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          network.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/routing_group_templates.rb b/server/lib/cimi/collections/routing_group_templates.rb
new file mode 100644
index 0000000..995b1f8
--- /dev/null
+++ b/server/lib/cimi/collections/routing_group_templates.rb
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class RoutingGroupTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :routing_group_templates do
+
+      operation :index do
+        description 'List all RoutingGroupTemplates in the RoutingGroupTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          routing_group_templates = RoutingGroupTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {routing_group_templates.to_xml}
+            format.json {routing_group_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific RoutingGroupTemplate'
+        control do
+          routing_group_template = RoutingGroupTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {routing_group_template.to_xml}
+            format.json {routing_group_template.to_json}
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/routing_groups.rb b/server/lib/cimi/collections/routing_groups.rb
new file mode 100644
index 0000000..5e7ccc5
--- /dev/null
+++ b/server/lib/cimi/collections/routing_groups.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class RoutingGroups < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :routing_groups do
+
+      operation :index do
+        description 'List all RoutingGroups in the RoutingGroupsCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          routing_groups = RoutingGroupCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {routing_groups.to_xml}
+            format.json {routing_groups.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific RoutingGroup'
+        control do
+          routing_group = RoutingGroup.find(params[:id], self)
+          respond_to do |format|
+            format.xml {routing_group.to_xml}
+            format.json {routing_group.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/volume_configurations.rb b/server/lib/cimi/collections/volume_configurations.rb
new file mode 100644
index 0000000..055e28c
--- /dev/null
+++ b/server/lib/cimi/collections/volume_configurations.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VolumeConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :volume_configurations do
+
+      operation :index do
+        description "Get list all VolumeConfigurations"
+        param :CIMISelect,  :string,  :optional
+        control do
+          volume_configuration = VolumeConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { volume_configuration.to_xml }
+            format.json { volume_configuration.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Get a specific VolumeConfiguration"
+        control do
+          volume_config = VolumeConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml { volume_config.to_xml }
+            format.json { volume_config.json }
+          end
+        end
+      end
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/volume_images.rb b/server/lib/cimi/collections/volume_images.rb
new file mode 100644
index 0000000..78432b1
--- /dev/null
+++ b/server/lib/cimi/collections/volume_images.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VolumeImages < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+
+    collection :volume_images do
+      description 'This entity represents an image that could be place on a pre-loaded volume.'
+
+      operation :index do
+        description "List all volumes images"
+        param :CIMISelect,  :string,  :optional
+        control do
+          volume_images = VolumeImageCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { volume_images.to_xml }
+            format.json { volume_images.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show a specific volume image"
+        control do
+          volume_image = VolumeImage.find(params[:id], self)
+          respond_to do |format|
+            format.xml { volume_image.to_xml }
+            format.json { volume_image.to_json }
+          end
+        end
+      end
+    end
+
+
+  end
+end
diff --git a/server/lib/cimi/collections/volumes.rb b/server/lib/cimi/collections/volumes.rb
new file mode 100644
index 0000000..1c45c9e
--- /dev/null
+++ b/server/lib/cimi/collections/volumes.rb
@@ -0,0 +1,80 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Volumes < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :volumes do
+
+      operation :index do
+        description "List all volumes"
+        param :CIMISelect,  :string,  :optional
+        control do
+          volumes = VolumeCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml { volumes.to_xml }
+            format.json { volumes.to_json }
+          end
+        end
+      end
+
+      operation :show do
+        description "Show specific Volume."
+        control do
+          volume = Volume.find(params[:id], self)
+          if volume
+            respond_to do |format|
+              format.xml  { volume.to_xml  }
+              format.json { volume.to_json }
+            end
+          else
+            report_error(404)
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new Volume."
+        control do
+          content_type = (request.content_type.end_with?("+json") ? :json  : :xml)
+          #((request.content_type.end_with?("+xml")) ? :xml : report_error(415) ) FIXME
+          case content_type
+          when :json
+            new_volume = Volume.create_from_json(request.body.read, self)
+          when :xml
+            new_volume = Volume.create_from_xml(request.body.read, self)
+          end
+          respond_to do |format|
+            format.json { new_volume.to_json }
+            format.xml { new_volume.to_xml }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified Volume"
+        param :id, :string, :required
+        control do
+          Volume.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+    end
+
+
+  end
+end
diff --git a/server/lib/cimi/collections/vsp_configurations.rb b/server/lib/cimi/collections/vsp_configurations.rb
new file mode 100644
index 0000000..31acceb
--- /dev/null
+++ b/server/lib/cimi/collections/vsp_configurations.rb
@@ -0,0 +1,48 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VspConfigurations < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :vsp_configurations do
+
+      operation :index do
+        description 'List all VSPConfigurations in the VSPConfigurationCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          vsp_configs = VSPConfigurationCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {vsp_configs.to_xml}
+            format.json {vsp_configs.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific VSPConfiguration'
+        control do
+          vsp_config = VSPConfiguration.find(params[:id], self)
+          respond_to do |format|
+            format.xml {vsp_config.to_xml}
+            format.json {vsp_config.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/vsp_templates.rb b/server/lib/cimi/collections/vsp_templates.rb
new file mode 100644
index 0000000..503de50
--- /dev/null
+++ b/server/lib/cimi/collections/vsp_templates.rb
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class VspTemplates < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :vsp_templates do
+
+      description 'The VSP Template is a set of Configuration values for realizing a VSP. A VSP Template may be used to create multiple VSPs'
+
+      operation :index do
+        description 'List all VSPTemplates in the VSPTemplateCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          vsp_templates = VSPTemplateCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {vsp_templates.to_xml}
+            format.json {vsp_templates.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific VSPTemplate'
+        control do
+          vsp_template = VSPTemplate.find(params[:id], self)
+          respond_to do |format|
+            format.xml {vsp_template.to_xml}
+            format.json {vsp_template.to_json}
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/collections/vsps.rb b/server/lib/cimi/collections/vsps.rb
new file mode 100644
index 0000000..52b1a5a
--- /dev/null
+++ b/server/lib/cimi/collections/vsps.rb
@@ -0,0 +1,108 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module CIMI::Collections
+  class Vsps < Base
+
+    check_capability :for => lambda { |m| driver.respond_to? m }
+    collection :vsps do
+
+      description 'A VSP represents the connection parameters of a network port'
+
+      operation :index do
+        description 'List all VSPs in the VSPCollection'
+        param :CIMISelect, :string, :optional
+        control do
+          vsps = VSPCollection.default(self).filter_by(params[:CIMISelect])
+          respond_to do |format|
+            format.xml {vsps.to_xml}
+            format.json {vsps.to_json}
+          end
+        end
+      end
+
+      operation :show do
+        description 'Show a specific VSP'
+        control do
+          vsp = VSP.find(params[:id], self)
+          respond_to do |format|
+            format.xml {vsp.to_xml}
+            format.json {vsp.to_json}
+          end
+        end
+      end
+
+      operation :create do
+        description "Create a new VSP"
+        control do
+          if request.content_type.end_with?("json")
+            vsp = CIMI::Model::VSP.create(request.body.read, self, :json)
+          else
+            vsp = CIMI::Model::VSP.create(request.body.read, self, :xml)
+          end
+          respond_to do |format|
+            format.xml { vsp.to_xml }
+            format.json { vsp.to_json }
+          end
+        end
+      end
+
+      operation :destroy do
+        description "Delete a specified VSP"
+        control do
+          CIMI::Model::VSP.delete!(params[:id], self)
+          no_content_with_status(200)
+        end
+      end
+
+      action :start do
+        description "Start specific VSP."
+        param :id,          :string,    :required
+        control do
+          vsp = VSP.find(params[:id], self)
+          report_error(404) unless vsp
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          vsp.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+      action :stop do
+        description "Stop specific VSP."
+        control do
+          vsp = VSP.find(params[:id], self)
+          report_error(404) unless vsp
+          if request.content_type.end_with?("json")
+            action = Action.from_json(request.body.read)
+          else
+            action = Action.from_xml(request.body.read)
+          end
+          vsp.perform(action, self) do |operation|
+            no_content_with_status(202) if operation.success?
+            # Handle errors using operation.failure?
+          end
+        end
+      end
+
+    end
+
+  end
+end
diff --git a/server/lib/cimi/helpers.rb b/server/lib/cimi/helpers.rb
new file mode 100644
index 0000000..4535c39
--- /dev/null
+++ b/server/lib/cimi/helpers.rb
@@ -0,0 +1,104 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud; end
+module CIMI; end
+
+require_relative '../deltacloud/drivers'
+require_relative '../deltacloud/models'
+require_relative '../deltacloud/helpers/driver_helper'
+require_relative '../deltacloud/helpers/auth_helper'
+require_relative '../deltacloud/helpers/url_helper'
+require_relative '../deltacloud/helpers/assets_helper'
+require_relative '../deltacloud/helpers/deltacloud_helper'
+require_relative '../deltacloud/helpers/rabbit_helper'
+require_relative '../deltacloud/helpers/rabbit_helper'
+require_relative '../deltacloud/core_ext/string'
+require_relative '../deltacloud/core_ext/array'
+require_relative '../deltacloud/core_ext/hash'
+require_relative '../deltacloud/core_ext/integer'
+require_relative '../deltacloud/core_ext/proc'
+require_relative './helpers/cimi_helper'
+require_relative './models'
+
+module CIMI::Collections
+  class Base < Sinatra::Base
+
+    extend Deltacloud::Helpers::Drivers
+    include Sinatra::Rabbit::Features
+    include CIMI::Model
+
+    helpers Deltacloud::Helpers::Drivers
+    helpers Sinatra::AuthHelper
+    helpers Sinatra::UrlForHelper
+    helpers Sinatra::StaticAssets::Helpers
+    helpers Rack::RespondTo::Helpers
+    helpers Deltacloud::Helpers::Application
+
+    register Rack::RespondTo
+
+    enable :xhtml
+    enable :dump_errors
+    enable :show_errors
+    disable :show_exceptions
+
+    set :root_url, API_ROOT_URL
+    set :version, API_VERSION
+    set :root, File.join(File.dirname(__FILE__), '..', '..')
+    set :views, root + '/views/cimi'
+    set :public_folder, root + '/public'
+
+    error do
+      report_error
+    end
+
+    error Deltacloud::ExceptionHandler::ValidationFailure do
+      report_error
+    end
+
+    before do
+      # Respond with 400, If we don't get a http Host header,
+      halt 400, "Unable to find HTTP Host header" if @env['HTTP_HOST'] == nil
+    end
+
+    after do
+      headers 'X-CIMI-Specification-Version' => API_VERSION
+    end
+
+    def self.new_route_for(route, &block)
+      get route_for('/' + route.to_s + '/new') do
+        instance_eval(&block) if block_given?
+        respond_to do |format|
+          format.html do
+            haml :"#{route}/new"
+          end
+        end
+      end
+    end
+
+    def self.check_capability(opts={})
+      Sinatra::Rabbit.set :check_capability, opts[:for]
+    end
+
+    def self.check_features(opts={})
+      Sinatra::Rabbit.set :check_features, opts[:for]
+    end
+
+    def self.route_for(url)
+      "#{settings.root_url}#{url}"
+    end
+
+  end
+end
diff --git a/server/lib/cimi/model.rb b/server/lib/cimi/model.rb
deleted file mode 100644
index fa3c771..0000000
--- a/server/lib/cimi/model.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-# Declare namespace for CIMI model
-#
-module CIMI
-  module Model; end
-end
-
-require 'cimi/model/schema'
-require 'cimi/model/base'
-require 'cimi/model/errors'
-require 'cimi/model/cloud_entry_point'
-require 'cimi/model/machine_template'
-require 'cimi/model/machine_image'
-require 'cimi/model/machine_configuration'
-require 'cimi/model/action'
-require 'cimi/model/machine'
-require 'cimi/model/volume'
-require 'cimi/model/machine_admin'
-require 'cimi/model/volume_configuration'
-require 'cimi/model/volume_image'
-require 'cimi/model/volume_template'
-require 'cimi/model/machine_template_collection'
-require 'cimi/model/machine_image_collection'
-require 'cimi/model/machine_configuration_collection'
-require 'cimi/model/machine_collection'
-require 'cimi/model/volume_collection'
-require 'cimi/model/machine_admin_collection'
-require 'cimi/model/volume_configuration_collection'
-require 'cimi/model/volume_image_collection'
-require 'cimi/model/volume_template_collection'
-require 'cimi/model/entity_metadata'
-require 'cimi/model/entity_metadata_collection'
-require 'cimi/model/network'
-require 'cimi/model/network_collection'
-require 'cimi/model/network_configuration'
-require 'cimi/model/network_configuration_collection'
-require 'cimi/model/network_template'
-require 'cimi/model/network_template_collection'
-require 'cimi/model/routing_group'
-require 'cimi/model/routing_group_collection'
-require 'cimi/model/routing_group_template'
-require 'cimi/model/routing_group_template_collection'
-require 'cimi/model/vsp'
-require 'cimi/model/vsp_collection'
-require 'cimi/model/vsp_configuration'
-require 'cimi/model/vsp_configuration_collection'
-require 'cimi/model/vsp_template'
-require 'cimi/model/vsp_template_collection'
-require 'cimi/model/address'
-require 'cimi/model/address_collection'
-require 'cimi/model/address_template'
-require 'cimi/model/address_template_collection'
diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb
new file mode 100644
index 0000000..b0793ee
--- /dev/null
+++ b/server/lib/cimi/models.rb
@@ -0,0 +1,75 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless require_relatived by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+require_relative '../deltacloud/drivers/features'
+
+# Declare namespace for CIMI models
+#
+
+module CIMI
+  module Model; end
+
+  class FakeCollection
+    extend Sinatra::Rabbit::Features
+    include Deltacloud::InstanceFeatures
+  end
+end
+
+require_relative './models/schema'
+require_relative './models/base'
+require_relative './models/errors'
+require_relative './models/entity_metadata'
+require_relative './models/entity_metadata_collection'
+require_relative './models/cloud_entry_point'
+require_relative './models/machine_template'
+require_relative './models/machine_image'
+require_relative './models/machine_configuration'
+require_relative './models/action'
+require_relative './models/machine'
+require_relative './models/volume'
+require_relative './models/machine_admin'
+require_relative './models/volume_configuration'
+require_relative './models/volume_image'
+require_relative './models/volume_template'
+require_relative './models/machine_template_collection'
+require_relative './models/machine_image_collection'
+require_relative './models/machine_configuration_collection'
+require_relative './models/machine_collection'
+require_relative './models/volume_collection'
+require_relative './models/machine_admin_collection'
+require_relative './models/volume_configuration_collection'
+require_relative './models/volume_image_collection'
+require_relative './models/volume_template_collection'
+require_relative './models/network'
+require_relative './models/network_collection'
+require_relative './models/network_configuration'
+require_relative './models/network_configuration_collection'
+require_relative './models/network_template'
+require_relative './models/network_template_collection'
+require_relative './models/routing_group'
+require_relative './models/routing_group_collection'
+require_relative './models/routing_group_template'
+require_relative './models/routing_group_template_collection'
+require_relative './models/vsp'
+require_relative './models/vsp_collection'
+require_relative './models/vsp_configuration'
+require_relative './models/vsp_configuration_collection'
+require_relative './models/vsp_template'
+require_relative './models/vsp_template_collection'
+require_relative './models/address'
+require_relative './models/address_collection'
+require_relative './models/address_template'
+require_relative './models/address_template_collection'
diff --git a/server/lib/cimi/server.rb b/server/lib/cimi/server.rb
index 60f9a3b..a1c7ef9 100644
--- a/server/lib/cimi/server.rb
+++ b/server/lib/cimi/server.rb
@@ -13,947 +13,48 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-require 'cimi/dependencies'
-require 'cimi/helpers/cimi_helper'
-require 'cimi/model'
+require 'rubygems'
+require 'crack'
+require 'json'
+require 'yaml'
+require 'haml'
+require 'sinatra/base'
+require 'sinatra/rabbit'
+require_relative '../sinatra'
 
-set :version, '0.1.0'
+require_relative './helpers'
+require_relative './collections'
 
-include Deltacloud::Drivers
-include CIMI::Model
+CMWG_NAMESPACE = "http://www.dmtf.org/cimi"
 
-set :drivers, Proc.new { driver_config }
+module CIMI
+  class API < Collections::Base
 
-Sinatra::Application.register Rack::RespondTo
+    # Enable logging
+    use Rack::CommonLogger
+    use Rack::Date
+    use Rack::ETag
+    use Rack::MatrixParams
+    use Rack::DriverSelect
+    use Rack::Accept
+    use Rack::MediaType
 
-use Rack::ETag
-use Rack::Runtime
-use Rack::MatrixParams
-use Rack::DriverSelect
-use Rack::MediaType
-use Rack::Date
-use Rack::CIMI
+    helpers CIMIHelper
 
-configure do
-  set :root_url, "/cimi"
-  set :views, File::join($top_srcdir, 'views', 'cimi')
-  set :public_folder, File::join($top_srcdir, 'public')
-  driver
-end
-
-configure :production do
-  use Rack::SyslogLogger
-  disable :logging
-  enable :show_errors
-  set :dump_errors, false
-  $stdout = SyslogFile.new
-  $stderr = $stdout
-end
-
-configure :development do
-  set :raise_errors => false
-  set :show_exceptions, false
-  $stdout.sync = true
-  $stderr.sync = true
-end
-
-# You could use $API_HOST environment variable to change your hostname to
-# whatever you want (eg. if you running API behind NAT)
-HOSTNAME=ENV['API_HOST'] ? ENV['API_HOST'] : nil
-
-error do
-  report_error
-end
-
-get "/" do
-  redirect settings.root_url
-end
-
-get "#{settings.root_url}\/?" do
-  halt 401 if params[:force_auth] and not driver.valid_credentials?(credentials)
-  redirect cloudEntryPoint_url, 301
-end
+    include Deltacloud::Helpers
+    include CIMI::Collections
+    include CIMI::Model
 
-global_collection  :cloudEntryPoint do
-  description 'Cloud entry point'
-  operation :index do
-    description "list all resources of the cloud"
-    control do
-      entry_point = CloudEntryPoint.create(self)
+    get API_ROOT_URL do
+      if params[:force_auth]
+        return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
+      end
+      entry_point = CIMI::Model::CloudEntryPoint.create(self)
       respond_to do |format|
         format.xml { entry_point.to_xml }
         format.json { entry_point.to_json }
       end
     end
-  end
-end
-
-global_collection :machine_configurations do
-  description 'List all machine configurations'
-
-  operation :index do
-    param :CIMISelect,  :string,  :optional
-    description "List all machine configurations"
-    control do
-      machine_configs = MachineConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machine_configs.to_xml }
-        format.json { machine_configs.to_json }
-      end
-    end
-  end
-
-  operation :show do
-
-    description "The Machine Configuration entity represents the set of configuration values "+
-      "that define the (virtual) hardware resources of a to-be-realized Machine Instance.."
-
-    param :id, :string, :required
-
-    control do
-      machine_conf = MachineConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine_conf.to_xml }
-        format.json { machine_conf.to_json }
-      end
-    end
-
-  end
-end
-
-global_collection :machine_images do
-  description 'List all machine images'
-
-  operation :index do
-    description "List all machine configurations"
-    param :CIMISelect,  :string,  :optional
-    control do
-      machine_images = MachineImageCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machine_images.to_xml }
-        format.json { machine_images.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific machine image."
-    param :id,          :string,    :required
-    control do
-      machine_image = MachineImage.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine_image.to_xml }
-        format.json { machine_image.to_json }
-      end
-    end
-  end
-
-end
-
-global_collection :machine_admins do
-  description 'Machine Admin entity'
-
-  operation :index do
-    description "List all machine admins"
-    param :CIMISelect,  :string,  :optional
-    with_capability :keys
-    control do
-      machine_admins = MachineAdminCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machine_admins.to_xml }
-        format.json { machine_admins.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific machine admin"
-    param :id,          :string,    :required
-    with_capability :key
-    control do
-      machine_admin = MachineAdmin.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine_admin.to_xml }
-        format.json { machine_admin.to_json }
-      end
-    end
-  end
-
-  operation :create do
-    description "Show specific machine admin"
-    with_capability :create_key
-    control do
-      if request.content_type.end_with?("+json")
-        new_admin = MachineAdmin.create_from_json(request.body.read, self)
-      else
-        new_admin = MachineAdmin.create_from_xml(request.body.read, self)
-      end
-      status 201 # Created
-      respond_to do |format|
-        format.json { new_admin.to_json }
-        format.xml { new_admin.to_xml }
-      end
-    end
-  end
-
-  operation :delete, :method => :delete, :member => true do
-    description "Delete specified MachineAdmin entity"
-    param :id,          :string,    :required
-    control do
-      MachineAdmin.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-end
-
-global_collection :machines do
-  description 'List all machine'
-
-  operation :index do
-    param :CIMISelect,  :string,  :optional
-    description "List all machines"
-    control do
-      machines = MachineCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { machines.to_xml }
-        format.json { machines.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      respond_to do |format|
-        format.xml { machine.to_xml }
-        format.json { machine.to_json }
-      end
-    end
-  end
 
-  operation :create do
-    description "Create a new Machine entity."
-    control do
-      if request.content_type.end_with?("+json")
-        new_machine = Machine.create_from_json(request.body.read, self)
-      else
-        new_machine = Machine.create_from_xml(request.body.read, self)
-      end
-      status 201 # Created
-      respond_to do |format|
-        format.json { new_machine.to_json }
-        format.xml { new_machine.to_xml }
-      end
-    end
   end
-
-  operation :destroy do
-    description "Delete a specified machine."
-    param :id,          :string,    :required
-    control do
-      Machine.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      if request.content_type.end_with?("+json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      machine.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :restart, :method => :post, :member => true do
-    description "Start specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      if request.content_type.end_with?("+json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      machine.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start specific machine."
-    param :id,          :string,    :required
-    control do
-      machine = Machine.find(params[:id], self)
-      if request.content_type.end_with?("+json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      machine.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-#NOTE: The routes for attach/detach used here are NOT as specified by CIMI
-#will likely move later. CIMI specifies PUT of the whole Machine description
-#with inclusion/ommission of the volumes you want [att|det]ached
-  operation :attach_volume, :method => :put, :member => true do
-    description "Attach CIMI Volume(s) to a machine."
-    param :id, :string, :required
-    control do
-      if request.content_type.end_with?("+json")
-        volumes_to_attach = Volume.find_to_attach_from_json(request.body.read, self)
-      else
-        volumes_to_attach = Volume.find_to_attach_from_xml(request.body.read, self)
-      end
-      machine = Machine.attach_volumes(volumes_to_attach, self)
-      respond_to do |format|
-        format.json{ machine.to_json}
-        format.xml{machine.to_xml}
-      end
-    end
-  end
-
-  operation :detach_volume, :method => :put, :member => true do
-    description "Detach CIMI Volume(s) from a machine."
-    param :id, :string, :required
-    control do
-      if request.content_type.end_with?("+json")
-        volumes_to_detach = Volume.find_to_attach_from_json(request.body.read, self)
-      else
-        volumes_to_detach = Volume.find_to_attach_from_xml(request.body.read, self)
-      end
-      machine = Machine.detach_volumes(volumes_to_detach, self)
-      respond_to do |format|
-        format.json{ machine.to_json}
-        format.xml{machine.to_xml}
-      end
-    end
-  end
-end
-
-global_collection :volumes do
-  description "Volume represents storage at either the block or file-system level. Volumes can be attached to Machines. Once attached, Volumes can be accessed by processes on that Machine"
-
-  operation :index do
-    description "List all volumes"
-    param :CIMISelect,  :string,  :optional
-    control do
-      volumes = VolumeCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { volumes.to_xml }
-        format.json { volumes.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show specific Volume."
-    param :id, :string, :required
-    control do
-      volume = Volume.find(params[:id], self)
-      if volume
-        respond_to do |format|
-          format.xml  { volume.to_xml  }
-          format.json { volume.to_json }
-        end
-      else
-        report_error(404)
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new Volume."
-    control do
-      content_type = (request.content_type.end_with?("+json") ? :json  : :xml)
-          #((request.content_type.end_with?("+xml")) ? :xml : report_error(415) ) FIXME
-      case content_type
-        when :json
-          new_volume = Volume.create_from_json(request.body.read, self)
-        when :xml
-          new_volume = Volume.create_from_xml(request.body.read, self)
-      end
-      respond_to do |format|
-        format.json { new_volume.to_json }
-        format.xml { new_volume.to_xml }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified Volume"
-    param :id, :string, :required
-    control do
-      Volume.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-end
-
-global_collection :volume_configurations do
-  description "The Volume Configuration entity represents the set of configuration values needed to create a Volume with certain characteristics. Volume Configurations are created by Providers and MAY, at the Providers discretion, be created by Consumers"
-
-  operation :index do
-    description "Get list all VolumeConfigurations"
-    param :CIMISelect,  :string,  :optional
-    control do
-      volume_configuration = VolumeConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { volume_configuration.to_xml }
-        format.json { volume_configuration.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Get a specific VolumeConfiguration"
-    param :id, :required, :string
-    control do
-      volume_config = VolumeConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml { volume_config.to_xml }
-        format.json { volume_config.json }
-      end
-    end
-  end
-
-global_collection :volume_images do
-  description 'This entity represents an image that could be place on a pre-loaded volume.'
-
-  operation :index do
-    description "List all volumes images"
-    param :CIMISelect,  :string,  :optional
-    control do
-      volume_images = VolumeImageCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { volume_images.to_xml }
-        format.json { volume_images.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show a specific volume image"
-    param :id, :string, :required
-    control do
-      volume_image = VolumeImage.find(params[:id], self)
-      respond_to do |format|
-        format.xml { volume_image.to_xml }
-        format.json { volume_image.to_json }
-      end
-    end
-  end
-
-end
-
-
-global_collection :entity_metadata do
-  description 'This allows for the discovery of Provider defined constraints on the CIMI defined attributes as well as discovery of any new extension attributes that the Provider may have defined.'
-
-  operation :index do
-    description "List all entity metadata defined for this provider"
-    control do
-      entity_metadata = EntityMetadataCollection.default(self)
-      respond_to do |format|
-        format.xml{entity_metadata.to_xml}
-        format.json{entity_metadata.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description "Get the entity metadata for a specific collection"
-    param :id, :required, :string
-    control do
-      entity_metadata = EntityMetadata.find(params[:id], self)
-      respond_to do |format|
-        format.xml{entity_metadata.to_xml}
-        format.json{entity_metadata.to_json}
-      end
-    end
-  end
-
-end
-
-global_collection :networks do
-  description 'A Network represents an abstraction of a layer 2 broadcast domain'
-
-  operation :index do
-    description "List all Networks"
-    param :CIMISelect,  :string,  :optional
-    control do
-      networks = NetworkCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { networks.to_xml }
-        format.json { networks.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description "Show a specific Network"
-    param :id, :string, :required
-    control do
-      network = Network.find(params[:id], self)
-      respond_to do |format|
-        format.xml { network.to_xml }
-        format.json { network.to_json }
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new Network"
-    control do
-      if request.content_type.end_with?("json")
-        network = Network.create(request.body.read, self, :json)
-      else
-        network = Network.create(request.body.read, self, :xml)
-      end
-      respond_to do |format|
-        format.xml { network.to_xml}
-        format.json { network.to_json }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified Network"
-    param :id, :string, :required
-    control do
-      Network.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start specific network."
-    param :id,          :string,    :required
-    control do
-      network = Network.find(params[:id], self)
-      report_error(404) unless network
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      network.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop specific network."
-    param :id,          :string,    :required
-    control do
-      network = Network.find(params[:id], self)
-      report_error(404) unless network
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      network.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :suspend, :method => :post, :member => true do
-    description "Suspend specific network."
-    param :id,          :string,    :required
-    control do
-      network = Network.find(params[:id], self)
-      report_error(404) unless network
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      network.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-end
-
-global_collection :network_configurations do
-  description 'Network Configurations contain the set of configuration values representing the information needed to create a Network with certain characteristics'
-
-  operation :index do
-    description 'List all NetworkConfigurations'
-    param :CIMISelect, :string, :optional
-    control do
-      network_configurations = NetworkConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml { network_configurations.to_xml  }
-        format.json { network_configurations.to_json }
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific NetworkConfiguration'
-    param :id, :string, :required
-    control do
-      network_config = NetworkConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml { network_config.to_xml }
-        format.json { network_config.to_json }
-      end
-    end
-  end
-end
-end
-
-global_collection :network_templates do
-
-  description 'Network Template is a set of configuration values for realizing a Network. An instance of Network Template may be used to create multiple Networks'
-
-  operation :index do
-    description 'List all Network Templates in the NetworkTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      network_templates = NetworkTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {network_templates.to_xml}
-        format.json {network_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific Network Template'
-    param :id, :string, :required
-    control do
-      network_template = NetworkTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {network_template.to_xml}
-        format.json {network_template.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :routing_groups do
-
-  description 'Routing Groups represent a collection of Networks that route to each other. Providers shall not allow two Networks to be routable to each other unless they are explicitly connected by being part of a common RoutingGroup.'
-
-  operation :index do
-    description 'List all RoutingGroups in the RoutingGroupsCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      routing_groups = RoutingGroupCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {routing_groups.to_xml}
-        format.json {routing_groups.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific RoutingGroup'
-    param :id, :string, :required
-    control do
-      routing_group = RoutingGroup.find(params[:id], self)
-      respond_to do |format|
-        format.xml {routing_group.to_xml}
-        format.json {routing_group.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :routing_group_templates do
-
-  description 'Routing Groups Templates capture the configuration values for realizing a RoutingGroup. A Routing Group Template may be used to create multiple RoutingGroups'
-
-  operation :index do
-    description 'List all RoutingGroupTemplates in the RoutingGroupTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      routing_group_templates = RoutingGroupTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {routing_group_templates.to_xml}
-        format.json {routing_group_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific RoutingGroupTemplate'
-    param :id, :string, :required
-    control do
-      routing_group_template = RoutingGroupTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {routing_group_template.to_xml}
-        format.json {routing_group_template.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :vsps do
-
-  description 'A VSP represents the connection parameters of a network port'
-
-  operation :index do
-    description 'List all VSPs in the VSPCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      vsps = VSPCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {vsps.to_xml}
-        format.json {vsps.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific VSP'
-    param :id, :string, :required
-    control do
-      vsp = VSP.find(params[:id], self)
-      respond_to do |format|
-        format.xml {vsp.to_xml}
-        format.json {vsp.to_json}
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new VSP"
-    control do
-      if request.content_type.end_with?("json")
-        vsp = CIMI::Model::VSP.create(request.body.read, self, :json)
-      else
-        vsp = CIMI::Model::VSP.create(request.body.read, self, :xml)
-      end
-      respond_to do |format|
-        format.xml { vsp.to_xml }
-        format.json { vsp.to_json }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified VSP"
-    param :id, :string, :required
-    control do
-      CIMI::Model::VSP.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-  operation :start, :method => :post, :member => true do
-    description "Start specific VSP."
-    param :id,          :string,    :required
-    control do
-      vsp = VSP.find(params[:id], self)
-      report_error(404) unless vsp
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      vsp.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-  operation :stop, :method => :post, :member => true do
-    description "Stop specific VSP."
-    param :id,          :string,    :required
-    control do
-      vsp = VSP.find(params[:id], self)
-      report_error(404) unless vsp
-      if request.content_type.end_with?("json")
-        action = Action.from_json(request.body.read)
-      else
-        action = Action.from_xml(request.body.read)
-      end
-      vsp.perform(action, self) do |operation|
-        no_content_with_status(202) if operation.success?
-        # Handle errors using operation.failure?
-      end
-    end
-  end
-
-end
-
-global_collection :vsp_configurations do
-
-  description 'A VSP Configuration is the set of configuration values representing the information needed to create a VSP with certain characteristics'
-
-  operation :index do
-    description 'List all VSPConfigurations in the VSPConfigurationCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      vsp_configs = VSPConfigurationCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {vsp_configs.to_xml}
-        format.json {vsp_configs.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific VSPConfiguration'
-    param :id, :string, :required
-    control do
-      vsp_config = VSPConfiguration.find(params[:id], self)
-      respond_to do |format|
-        format.xml {vsp_config.to_xml}
-        format.json {vsp_config.to_json}
-      end
-    end
-  end
-
-end
-
-
-global_collection :vsp_templates do
-
-  description 'The VSP Template is a set of Configuration values for realizing a VSP. A VSP Template may be used to create multiple VSPs'
-
-  operation :index do
-    description 'List all VSPTemplates in the VSPTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      vsp_templates = VSPTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {vsp_templates.to_xml}
-        format.json {vsp_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific VSPTemplate'
-    param :id, :string, :required
-    control do
-      vsp_template = VSPTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {vsp_template.to_xml}
-        format.json {vsp_template.to_json}
-      end
-    end
-  end
-
-end
-
-global_collection :addresses do
-
-  description 'An Address represents an IP address, and its associated metdata, for a particular Network.'
-
-  operation :index do
-    description 'List all Addresses in the AddressCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      addresses = AddressCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {addresses.to_xml}
-        format.json {addresses.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific Address'
-    param :id, :string, :required
-    control do
-      address = CIMI::Model::Address.find(params[:id], self)
-      respond_to do |format|
-        format.xml {address.to_xml}
-        format.json {address.to_json}
-      end
-    end
-  end
-
-  operation :create do
-    description "Create a new Address"
-    control do
-      if request.content_type.end_with?("json")
-        address = CIMI::Model::Address.create(request.body.read, self, :json)
-      else
-        address = CIMI::Model::Address.create(request.body.read, self, :xml)
-      end
-      respond_to do |format|
-        format.xml { address.to_xml }
-        format.json { address.to_json }
-      end
-    end
-  end
-
-  operation :destroy do
-    description "Delete a specified Address"
-    param :id, :string, :required
-    control do
-      CIMI::Model::Address.delete!(params[:id], self)
-      no_content_with_status(200)
-    end
-  end
-
-end
-
-
-global_collection :address_templates do
-
-  description 'An AddressTemplate captures the configuration values for realizing an Address. An Address Template may be used to create multiple Addresses.'
-
-  operation :index do
-    description 'List all AddressTemplates in the AddressTemplateCollection'
-    param :CIMISelect, :string, :optional
-    control do
-      address_templates = AddressTemplateCollection.default(self).filter_by(params[:CIMISelect])
-      respond_to do |format|
-        format.xml {address_templates.to_xml}
-        format.json {address_templates.to_json}
-      end
-    end
-  end
-
-  operation :show do
-    description 'Show a specific AddressTemplate'
-    param :id, :string, :required
-    control do
-      address_template = CIMI::Model::AddressTemplate.find(params[:id], self)
-      respond_to do |format|
-        format.xml {address_template.to_xml}
-        format.json {address_template.to_json}
-      end
-    end
-  end
-
 end
-- 
1.7.10


[PATCH core 16/32] Core: Removed backend capability checking, is part of Rabbit now

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


Signed-off-by: Michal fojtik <mf...@redhat.com>
---
 server/lib/deltacloud/backend_capability.rb      |   42 ------------
 server/lib/deltacloud/base_driver/mock_driver.rb |   78 ----------------------
 2 files changed, 120 deletions(-)
 delete mode 100644 server/lib/deltacloud/backend_capability.rb
 delete mode 100644 server/lib/deltacloud/base_driver/mock_driver.rb

diff --git a/server/lib/deltacloud/backend_capability.rb b/server/lib/deltacloud/backend_capability.rb
deleted file mode 100644
index 7f19007..0000000
--- a/server/lib/deltacloud/backend_capability.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-module Deltacloud::BackendCapability
-
-  attr_reader :capability
-
-  def with_capability(capability)
-    @capability = capability
-  end
-
-  def has_capability?(backend)
-    !capability or backend.has_capability?(capability)
-  end
-
-  def check_capability(backend)
-    if !has_capability?(backend)
-      raise Deltacloud::ExceptionHandler::NotSupported.new("#{capability} capability not supported by backend #{backend.class.name}")
-    end
-  end
-
-  module Helpers
-    def operations_for_collection(collection)
-      collections[collection].operations.values.select { |op| op.has_capability?(driver) }
-    end
-  end
-
-  helpers Helpers
-end
diff --git a/server/lib/deltacloud/base_driver/mock_driver.rb b/server/lib/deltacloud/base_driver/mock_driver.rb
deleted file mode 100644
index 7956281..0000000
--- a/server/lib/deltacloud/base_driver/mock_driver.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.  The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/method_serializer'
-
-# Create 'mock' version of original driver client/gem:
-
-# Initialize driver and include Deltacloud
-include Deltacloud
-driver
-
-module Mock
-
-  class Ec2 < Aws::Ec2
-
-    include MethodSerializer::Cache
-
-    def self.cached_methods
-      [
-        :describe_images,
-        :describe_images_by_owner,
-        :describe_availability_zones,
-        :launch_instances,
-        :describe_instances,
-        :reboot_instances,
-        :create_tag,
-        :delete_tag,
-        :describe_tags,
-        :terminate_instances,
-        :describe_key_pairs,
-        :create_key_pair,
-        :delete_key_pair,
-        :create_volume,
-        :get_console_output,
-        :describe_volumes,
-        :delete_volume,
-        :attach_volume,
-        :detach_volume,
-        :describe_snapshots,
-        :associate_address,
-        :try_create_snapshot,
-      ]
-    end
-
-    MethodSerializer::Cache::wrap_methods(self, :cache_dir => File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'tests', 'ec2', 'support'))
-  end
-
-end
-
-
-# Replace original client with mock client
-Deltacloud::Drivers::EC2::EC2Driver.class_eval do
-  alias_method :original_new_client, :new_client
-
-  def new_client(credentials, provider = :ec2)
-    auth_credentials = { :access_key_id => credentials.user, :secret_access_key => credentials.password}
-    if provider == :elb
-      Mock::ELB.new(auth_credentials)
-    elsif provider == :s3
-      Mock::S3.new(auth_credentials)
-    else
-      Mock::Ec2.new(auth_credentials[:access_key_id], auth_credentials[:secret_access_key])
-    end
-  end
-
-end
-- 
1.7.10


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

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


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

diff --git a/server/views/api/show.html.haml b/server/views/api/show.html.haml
index 265739d..66d1f3a 100644
--- a/server/views/api/show.html.haml
+++ b/server/views/api/show.html.haml
@@ -3,10 +3,11 @@
 
 %div{ :'data-role' => :content, :'data-theme' => 'c'}
   %ul{ :'data-role' => :listview, :'data-inset' => 'true'}
-    - @collections.sort_by { |k| k.to_s }.each do |key|
-      %li= link_to key.to_s.gsub('_', ' ').titlecase, api_url_for(key), :'data-icon' => "arrow-r", :'data-ajax' => false
+    - Deltacloud.collections.each do |c|
+      - next unless c.operation(:index).has_capability?
+      %li= link_to c.collection_name.to_s.gsub('_', ' ').titlecase, api_url_for(c.collection_name), :'data-icon' => "arrow-r", :'data-ajax' => false
 
-- if @providers.size > 1
+- unless driver.configured_providers.empty?
   %div{ :'data-role' => :footer, :'data-theme' => 'a'}
     %form{ :action => settings.root_url, :method => :post, :'data-ajax' => 'false'}
       - if @driver_name
diff --git a/server/views/api/show.xml.haml b/server/views/api/show.xml.haml
index 2b9f653..ad2df09 100644
--- a/server/views/api/show.xml.haml
+++ b/server/views/api/show.xml.haml
@@ -1,7 +1,6 @@
-%api{ :version => settings.version, :driver => driver_symbol }
-  - for entry_point in entry_points
-    %link{ :rel=>entry_point[0], :href=>entry_point[1] }
-      - for feature in driver.features(entry_point[0])
-        %feature{ :name=>feature.name }
-          - for name,value in feature.constraints
-            %constraint{ :name=>name, :value=>value }
+%api{ :version => settings.version, :driver => driver_symbol, :provider => Thread.current[:provider] || ENV['API_PROVIDER'] }
+  - Deltacloud.collections.each do |c|
+    - next unless c.operation(:index).has_capability?
+    %link{ :rel => c.collection_name, :href => self.send(:"#{c.collection_name}_url")}
+      - c.features.select { |f| driver.class.has_feature?(c.collection_name, f.name) }.each do |f|
+        %feature{ :name => f.name }
-- 
1.7.10