deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@redhat.com
Subject [PATCH core 1/5] Client: Complete rewrite of deltacloud-client
Date Thu, 07 Mar 2013 13:10:24 GMT
From: Michal Fojtik <mfojtik@redhat.com>

- Now use Faraday HTTP lib
- Superb error reporting (based on Faraday middleware)
- Documentation
- Easy to read/fix bugs/add features
- Compatible with jRuby/MRI 2.0.0

Signed-off-by: Michal fojtik <mfojtik@redhat.com>
---
 client/.gitignore                                  |  21 +-
 client/Gemfile                                     |  12 +
 client/README                                      | 127 ------
 client/README.md                                   |  73 ++++
 client/Rakefile                                    |  92 +++-
 client/deltacloud-client.gemspec                   |  13 +-
 client/lib/base_object.rb                          | 386 ----------------
 client/lib/client_bucket_methods.rb                |  69 ---
 client/lib/deltacloud.rb                           | 486 ---------------------
 client/lib/deltacloud/client.rb                    |  78 ++++
 client/lib/deltacloud/client/base_error.rb         |  84 ++++
 client/lib/deltacloud/client/connection.rb         | 135 ++++++
 .../lib/deltacloud/client/helpers/model_helper.rb  |  69 +++
 .../deltacloud/client/helpers/property_helper.rb   | 103 +++++
 client/lib/deltacloud/client/helpers/xml_helper.rb |  33 ++
 client/lib/deltacloud/client/methods.rb            |  29 ++
 client/lib/deltacloud/client/methods/address.rb    |  68 +++
 client/lib/deltacloud/client/methods/api.rb        |  96 ++++
 .../client/methods/backward_compatiblity.rb        |  72 +++
 client/lib/deltacloud/client/methods/blob.rb       |  91 ++++
 client/lib/deltacloud/client/methods/bucket.rb     |  56 +++
 client/lib/deltacloud/client/methods/common.rb     |  46 ++
 client/lib/deltacloud/client/methods/driver.rb     |  54 +++
 client/lib/deltacloud/client/methods/firewall.rb   |  66 +++
 .../deltacloud/client/methods/hardware_profile.rb  |  42 ++
 client/lib/deltacloud/client/methods/image.rb      |  62 +++
 client/lib/deltacloud/client/methods/instance.rb   | 140 ++++++
 .../deltacloud/client/methods/instance_state.rb    |  41 ++
 client/lib/deltacloud/client/methods/key.rb        |  59 +++
 client/lib/deltacloud/client/methods/realm.rb      |  43 ++
 .../deltacloud/client/methods/storage_snapshot.rb  |  62 +++
 .../deltacloud/client/methods/storage_volume.rb    |  95 ++++
 client/lib/deltacloud/client/models.rb             |  30 ++
 client/lib/deltacloud/client/models/address.rb     |  57 +++
 client/lib/deltacloud/client/models/base.rb        | 151 +++++++
 client/lib/deltacloud/client/models/blob.rb        |  56 +++
 client/lib/deltacloud/client/models/bucket.rb      |  65 +++
 client/lib/deltacloud/client/models/driver.rb      |  87 ++++
 client/lib/deltacloud/client/models/firewall.rb    |  70 +++
 .../deltacloud/client/models/hardware_profile.rb   |  68 +++
 client/lib/deltacloud/client/models/image.rb       |  60 +++
 client/lib/deltacloud/client/models/instance.rb    | 122 ++++++
 .../deltacloud/client/models/instance_address.rb   |  35 ++
 .../lib/deltacloud/client/models/instance_state.rb |  52 +++
 client/lib/deltacloud/client/models/key.rb         |  52 +++
 client/lib/deltacloud/client/models/realm.rb       |  29 ++
 .../deltacloud/client/models/storage_snapshot.rb   |  54 +++
 .../lib/deltacloud/client/models/storage_volume.rb |  96 ++++
 client/lib/deltacloud/core_ext.rb                  |  19 +
 client/lib/deltacloud/core_ext/element.rb          |  32 ++
 client/lib/deltacloud/core_ext/fixnum.rb           |  30 ++
 client/lib/deltacloud/core_ext/nil.rb              |  22 +
 client/lib/deltacloud/core_ext/string.rb           |  49 +++
 client/lib/deltacloud/error_response.rb            |  92 ++++
 client/lib/documentation.rb                        |  59 ---
 client/lib/errors.rb                               | 140 ------
 client/lib/hwp_properties.rb                       |  61 ---
 client/lib/instance_state.rb                       |  44 --
 client/lib/string.rb                               |  59 ---
 client/support/method_test_template.erb            |  53 +++
 client/support/methods_template.erb                |  54 +++
 client/support/model_template.erb                  |  45 ++
 62 files changed, 3304 insertions(+), 1442 deletions(-)
 create mode 100644 client/Gemfile
 delete mode 100644 client/README
 create mode 100644 client/README.md
 delete mode 100644 client/lib/base_object.rb
 delete mode 100644 client/lib/client_bucket_methods.rb
 delete mode 100644 client/lib/deltacloud.rb
 create mode 100644 client/lib/deltacloud/client.rb
 create mode 100644 client/lib/deltacloud/client/base_error.rb
 create mode 100644 client/lib/deltacloud/client/connection.rb
 create mode 100644 client/lib/deltacloud/client/helpers/model_helper.rb
 create mode 100644 client/lib/deltacloud/client/helpers/property_helper.rb
 create mode 100644 client/lib/deltacloud/client/helpers/xml_helper.rb
 create mode 100644 client/lib/deltacloud/client/methods.rb
 create mode 100644 client/lib/deltacloud/client/methods/address.rb
 create mode 100644 client/lib/deltacloud/client/methods/api.rb
 create mode 100644 client/lib/deltacloud/client/methods/backward_compatiblity.rb
 create mode 100644 client/lib/deltacloud/client/methods/blob.rb
 create mode 100644 client/lib/deltacloud/client/methods/bucket.rb
 create mode 100644 client/lib/deltacloud/client/methods/common.rb
 create mode 100644 client/lib/deltacloud/client/methods/driver.rb
 create mode 100644 client/lib/deltacloud/client/methods/firewall.rb
 create mode 100644 client/lib/deltacloud/client/methods/hardware_profile.rb
 create mode 100644 client/lib/deltacloud/client/methods/image.rb
 create mode 100644 client/lib/deltacloud/client/methods/instance.rb
 create mode 100644 client/lib/deltacloud/client/methods/instance_state.rb
 create mode 100644 client/lib/deltacloud/client/methods/key.rb
 create mode 100644 client/lib/deltacloud/client/methods/realm.rb
 create mode 100644 client/lib/deltacloud/client/methods/storage_snapshot.rb
 create mode 100644 client/lib/deltacloud/client/methods/storage_volume.rb
 create mode 100644 client/lib/deltacloud/client/models.rb
 create mode 100644 client/lib/deltacloud/client/models/address.rb
 create mode 100644 client/lib/deltacloud/client/models/base.rb
 create mode 100644 client/lib/deltacloud/client/models/blob.rb
 create mode 100644 client/lib/deltacloud/client/models/bucket.rb
 create mode 100644 client/lib/deltacloud/client/models/driver.rb
 create mode 100644 client/lib/deltacloud/client/models/firewall.rb
 create mode 100644 client/lib/deltacloud/client/models/hardware_profile.rb
 create mode 100644 client/lib/deltacloud/client/models/image.rb
 create mode 100644 client/lib/deltacloud/client/models/instance.rb
 create mode 100644 client/lib/deltacloud/client/models/instance_address.rb
 create mode 100644 client/lib/deltacloud/client/models/instance_state.rb
 create mode 100644 client/lib/deltacloud/client/models/key.rb
 create mode 100644 client/lib/deltacloud/client/models/realm.rb
 create mode 100644 client/lib/deltacloud/client/models/storage_snapshot.rb
 create mode 100644 client/lib/deltacloud/client/models/storage_volume.rb
 create mode 100644 client/lib/deltacloud/core_ext.rb
 create mode 100644 client/lib/deltacloud/core_ext/element.rb
 create mode 100644 client/lib/deltacloud/core_ext/fixnum.rb
 create mode 100644 client/lib/deltacloud/core_ext/nil.rb
 create mode 100644 client/lib/deltacloud/core_ext/string.rb
 create mode 100644 client/lib/deltacloud/error_response.rb
 delete mode 100644 client/lib/documentation.rb
 delete mode 100644 client/lib/errors.rb
 delete mode 100644 client/lib/hwp_properties.rb
 delete mode 100644 client/lib/instance_state.rb
 delete mode 100644 client/lib/string.rb
 create mode 100644 client/support/method_test_template.erb
 create mode 100644 client/support/methods_template.erb
 create mode 100644 client/support/model_template.erb

diff --git a/client/.gitignore b/client/.gitignore
index b4b07a3..3a0a93e 100644
--- a/client/.gitignore
+++ b/client/.gitignore
@@ -1,4 +1,19 @@
-spec_report.html
-*.swp
-tmp/
 *.gem
+*.rbc
+.bundle
+.config
+coverage
+InstalledFiles
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
+*.lock
+
+# YARD artifacts
+.yardoc
+_yardoc
+doc/
diff --git a/client/Gemfile b/client/Gemfile
new file mode 100644
index 0000000..4c6d274
--- /dev/null
+++ b/client/Gemfile
@@ -0,0 +1,12 @@
+source 'https://rubygems.org'
+
+gem 'faraday'
+gem 'nokogiri'
+
+group :development do
+  gem 'rake'
+  gem 'minitest'
+  gem 'vcr'
+  gem 'pry'
+  gem 'simplecov', :require => false
+end
diff --git a/client/README b/client/README
deleted file mode 100644
index 5324062..0000000
--- a/client/README
+++ /dev/null
@@ -1,127 +0,0 @@
-# Deltacloud Client (Ruby)
-
-The Deltacloud project includes a Ruby client.  Other language-bindings
-are possible and will be supported soon.  The client aims to insulate
-users from having to deal with HTTP and REST directly.
-
-Each resource type has an associated model to ease usage.  Where
-resource reference other resources, natural navigation across the
-object model is possible.
-
-For example
-
-    puts instance.image.name
-    puts instance.hardware_profile.architecture
-
-## Basics
-
-To use the client, you must require `deltacloud`.
-
-    require 'deltacloud'
-
-## Connecting to a Deltacloud provider
-
-    require 'deltacloud'
-
-    api_url      = 'http://localhost:3001/api'
-    api_name     = 'mockuser'
-    api_password = 'mockpassword'
-
-    client = DeltaCloud.new( api_name, api_password, api_url )
-
-    # work with client here
-
-In addition to creating a client, operations may occur within a block
-included on the initialization
-
-    DeltaCloud.new( api_name, api_password, api_url ) do |client|
-      # work with client here
-    end
-
-In the event of a failure, any underlying HTTP transport exceptions
-will be thrown all the way out to the caller.
-
-## Listing realms
-
-You may retrieve a complete list of realms available to you
-
-    realms = client.realms
-
-You may retrieve a specific realm by its identifier
-
-    realm = client.realm( 'us' )
-
-## Listing hardware profiles
-
-You may retrieve a complete list of hardware profiles available for launching
-machines
-
-    hwp = client.hardware_profiles
-
-You may filter hardware profiles by architecture
-
-    flavors = client.hardware_profiles( :architecture=>'x86_64' )
-
-You may retrieve a specific hardware profile by its identifier
-
-    flavor = client.hardware_profile( 'm1-small' )
-
-## Listing images
-
-You may retrieve a complete list of images
-
-    images = client.images
-
-You may retrieve a list of images owned by the currently authenticated
-user
-
-    images = client.images( :owner_id=>:self )
-
-You may retrieve a list of images visible to you but owned by a specific
-user
-
-    images = client.images( :owner_id=>'daryll' )
-
-You may retrieve a specific image by its identifier
-
-    image = client.image( 'ami-8675309' )
-
-## Listing instances
-
-You may retrieve a list of all instances visible to you
-
-    instances = client.instances
-
-You may retrieve a specific instance by its identifier
-
-    instance = client.instance( 'i-90125' )
-
-## Launching instances
-
-An instance may be launched using just an image identifier
-
-    image = client.image( 'ami-8675309' )
-    instance = client.create_instance( image.id )
-
-Optionally, a flavor or realm may be specified
-
-    instance = client.create_instance( image.id, :flavor=>'m1-small', :realm=>'us' )
-
-## Manipulating instances
-
-Given an instance, depending on its state, various actions _may_ be available.
-
-To determine what's available, the `instance#actions` method may be used.
-
-    instance.actions # [ 'reboot', 'stop' ]
-
-For a valid action, the method matching the action with an exclamation point may be called.
-
-    instance.reboot!
-
-Upon invoking an action, the instance will refresh its contents, in case the state has changed.
-To determine later if the state has changed again, the instance must be refetched using
-the `client.instance(...)` method.
-
-
-
diff --git a/client/README.md b/client/README.md
new file mode 100644
index 0000000..fcd7595
--- /dev/null
+++ b/client/README.md
@@ -0,0 +1,73 @@
+# deltacloud-client
+
+The Deltacloud project includes a Ruby client.  Other language-bindings
+are possible and will be supported soon.  The client aims to insulate
+users from having to deal with HTTP and REST directly.
+
+Each resource type has an associated model to ease usage.  Where
+resource reference other resources, natural navigation across the
+object model is possible.
+
+This is a Ruby client library for the [Deltacloud API](http://deltacloud.apache.org).
+
+## Usage
+
+```ruby
+require 'deltacloud/client'
+
+API_URL = "http://localhost:3001/api" # Deltacloud API endpoint
+
+# Simple use-cases
+client = Deltacloud::Client(API_URL, 'mockuser', 'mockpassword')
+
+pp client.instances           # List all instances
+pp client.instance('i-12345') # Get one instance
+
+inst = client.create_instance 'ami-1234', :hwp_id => 'm1.small' # Create instance
+
+inst.reboot!  # Reboot instance
+
+# Advanced usage
+
+# Deltacloud API supports changing driver per-request:
+
+client.use(:ec2, 'API_KEY', 'API_SECRET').instances # List EC2 instances
+client.use(:openstack, 'admin@tenant', 'password', KEYSTONE_URL).instances # List Openstack instances
+
+```
+# Want help?
+
+## Adding new Deltacloud collection to client
+
+```
+$ rake generate[YOUR_COLLECTION] # eg. 'storage_snapshot'
+# Hit Enter 2x
+```
+
+- Edit `lib/deltacloud/client/methods/YOUR_COLLECTION.rb` and add all
+  methods for manipulating your collection. The list/show methods
+  should already be generated for you, but double-check them.
+
+- Edit `lib/deltacloud/client/model/YOUR_COLLECTION.rb` and add model
+  methods. Model methods should really be just a syntax sugar and exercise
+  the *Deltacloud::Client::Methods* methods.
+  The purpose of *model* class life is to deserialize XML body received
+  from Deltacloud API to a Ruby class.
+
+## Debugging a nasty bug?
+
+- You can easily debug deltacloud-client using powerful **pry**.
+
+  - `gem install deltacloud-core`
+  - optional: `rbenv rehash` ;-)
+  - `deltacloudd -i mock -p 3002`
+  - `rake console`
+
+Console require **pry** gem installed. If you are not using this awesome
+gem, you can fix it by `gem install pry`.
+
+# License
+
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
diff --git a/client/Rakefile b/client/Rakefile
index 4248ca5..17d0cdd 100644
--- a/client/Rakefile
+++ b/client/Rakefile
@@ -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,12 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+require 'rubygems'
 require 'rubygems/package_task'
+require 'rake'
 require 'rake/testtask'
 
-load 'deltacloud-client.gemspec'
+require 'pry' rescue LoadError
 
 spec = Gem::Specification.load('deltacloud-client.gemspec')
 
@@ -25,15 +26,98 @@ Gem::PackageTask.new(spec) do |pkg|
   pkg.need_tar = true
 end
 
-desc "Re-install the deltacloud-client gem"
+desc "Re-install the deltacloud-client gem (used for development)"
 task :reinstall do
   puts %x{gem uninstall deltacloud-client --all -I -x}
   puts %x{gem build deltacloud-client.gemspec}
   puts %x{gem install deltacloud-client-*.gem --local}
 end
 
+desc 'Generate model/methods files for collection.'
+task :generate, :name do |t, args|
+  require 'erb'
+  require_relative './lib/deltacloud/core_ext'
+  model_tpl = ERB.new(File.read('support/model_template.erb'))
+  methods_tpl = ERB.new(File.read('support/methods_template.erb'))
+  name = args[:name]
+  model_file = "lib/deltacloud/client/models/#{name}.rb"
+  methods_file = "lib/deltacloud/client/methods/#{name}.rb"
+  puts model_body = model_tpl.result(binding)
+  print "Save model to '#{model_file}'? [Y/n]"
+  answer = $stdin.gets.chomp
+  if answer.empty? or answer == 'Y'
+    File.open(model_file, 'w') { |f|
+      f.write(model_body)
+    }
+    File.open('lib/deltacloud/client/models.rb', 'a') { |f|
+      f.puts "require_relative './models/#{name}'"
+    }
+  end
+  puts methods_body = methods_tpl.result(binding)
+  print "Save methods to '#{methods_file}'? [Y/n]"
+  answer = $stdin.gets.chomp
+  if answer.empty? or answer == 'Y'
+    File.open(methods_file, 'w') { |f|
+      f.write(methods_body)
+    }
+    File.open('lib/deltacloud/client/methods.rb', 'a') { |f|
+      f.puts "require_relative './methods/#{name}'"
+    }
+  end
+  puts
+  puts "Don't forget to add this line to 'lib/deltacloud/client/connection.rb':"
+  puts
+  puts "include Deltacloud::Client::Methods::#{name.to_s.camelize}"
+  puts
+end
+
+desc 'Generate method test file'
+task :test_generate, :name do |t, args|
+  require 'erb'
+  require_relative './lib/deltacloud/core_ext'
+  method_tpl = ERB.new(File.read('support/method_test_template.erb'))
+  name = args[:name]
+  methods_file = "tests/methods/#{name}_test.rb"
+  puts method_body = method_tpl.result(binding)
+  print "Save method test to '#{methods_file}'? [Y/n]"
+  answer = $stdin.gets.chomp
+  if answer.empty? or answer == 'Y'
+    File.open(methods_file, 'w') { |f|
+      f.write(method_body)
+    }
+  end
+end
+
+
+desc "Open console with client connected to #{ENV['API_URL'] || 'localhost:3002/api'}"
+task :console do
+  unless binding.respond_to? :pry
+    puts 'To open a console, you need to have "pry" installed (gem install pry)'
+    exit(1)
+  end
+  require_relative './lib/deltacloud/client'
+  client = Deltacloud::Client(
+    ENV['API_URL'] || 'http://localhost:3002/api',
+    ENV['API_USER'] || 'mockuser',
+    ENV['API_PASSWORD'] || 'mockpassword'
+  )
+  binding.pry
+end
+
 Rake::TestTask.new(:test) do |t|
   t.test_files = FileList[
-    'tests/*test.rb',                     # EC2 frontend internal API tests
+    'tests/*/*_test.rb'
   ]
 end
+
+desc "Execute test against live Deltacloud API"
+task :test_live do
+  ENV['NO_VCR'] = 'true'
+  Rake::Task[:test].invoke
+end
+
+desc "Generate test coverage report"
+task :coverage do
+  ENV['COVERAGE'] = 'true'
+  Rake::Task[:test].invoke
+end
diff --git a/client/deltacloud-client.gemspec b/client/deltacloud-client.gemspec
index 1b14f43..874e2f0 100644
--- a/client/deltacloud-client.gemspec
+++ b/client/deltacloud-client.gemspec
@@ -20,14 +20,19 @@ Gem::Specification.new do |s|
   s.homepage = "http://www.deltacloud.org"
   s.email = 'dev@deltacloud.apache.org'
   s.name = 'deltacloud-client'
-  s.description = %q{Deltacloud REST Client for API}
+  s.description = %q{A REST client for the Deltacloud API}
   s.version = Deltacloud::API_VERSION
   s.summary = %q{Deltacloud REST Client}
   s.files = Dir['Rakefile', 'lib/**/*.rb']
   s.test_files= Dir.glob("tests/**/**")
-  s.extra_rdoc_files = Dir["LICENSE", "NOTICE", "DISCLAIMER"]
+  s.extra_rdoc_files = Dir["LICENSE", "NOTICE", "README.md"]
 
-  s.add_dependency('rest-client', '>= 1.6.1')
+  s.add_dependency('faraday', '>=0.8.6')
   s.add_dependency('nokogiri', '>= 1.4.3')
-  s.add_development_dependency('rspec', '>= 2.0.0')
+
+  s.add_development_dependency('minitest')
+  s.add_development_dependency('simplecov')
+  s.add_development_dependency('vcr')
+  s.add_development_dependency('rake')
+  s.add_development_dependency('pry')
 end
diff --git a/client/lib/base_object.rb b/client/lib/base_object.rb
deleted file mode 100644
index 6a28d5a..0000000
--- a/client/lib/base_object.rb
+++ /dev/null
@@ -1,386 +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_relative './string.rb'
-
-module DeltaCloud
-
-    class BaseObjectParamError < Exception; end
-    class NoHandlerForMethod < Exception; end
-
-    # BaseObject model basically provide the basic operation around
-    # REST model, like defining a links between different objects,
-    # element with text values, or collection of these elements
-    class BaseObject
-      attr_reader :id, :url, :client, :base_name
-      attr_reader :objects
-
-      alias :uri :url
-
-      # For initializing new object you require to set
-      # id, url, client and name attribute.
-      def initialize(opts={}, &block)
-        @id, @url, @client, @base_name = opts[:id], opts[:url], opts[:client], opts[:name]
-        @objects = []
-        raise BaseObjectParamError if @id.nil? or @url.nil? or @client.nil? or @base_name.nil?
-        yield self if block_given?
-      end
-
-      # This method add link to another object in REST model
-      # XML syntax: <link rel="destroy" href="http://localhost/api/resource" method="post"/>
-      def add_link!(object_name, id)
-        @objects << {
-          :type => :link,
-          :method_name => object_name.sanitize,
-          :id => id
-        }
-        @objects << {
-          :type => :text,
-          :method_name => "#{object_name.sanitize}_id",
-          :value => id
-        }
-      end
-
-      # Method add property for hardware profile
-      def add_hwp_property!(name, property, type)
-        hwp_property=case type
-          when :float then DeltaCloud::HWP::FloatProperty.new(property, name)
-          when :integer then DeltaCloud::HWP::Property.new(property, name)
-        end
-        @objects << {
-          :type => :property,
-          :method_name => name.sanitize,
-          :property => hwp_property
-        }
-      end
-
-      # This method define text object in REST model
-      # XML syntax: <name>Instance 1</name>
-      def add_text!(object_name, value)
-        @objects << {
-          :type => :text,
-          :method_name => object_name.sanitize,
-          :value => value
-        }
-      end
-
-      def add_authentication!(auth_type, values=[])
-        value = { :key => (values/'login/keyname').text.strip } if auth_type == 'key'
-        if auth_type == 'password'
-          value = {
-            :username => (values/'login/username').text.strip,
-            :username => (values/'login/password').text.strip
-          }
-        end
-        @objects << {
-          :type => :collection,
-          :method_name => 'authentication',
-          :values => value
-        }
-      end
-
-      def add_provider!(provider_id, entrypoints)
-        @providers ||= []
-        @providers << {
-          provider_id.intern => entrypoints.map { |e| { :kind => e[:kind], :url => e.text } }
-        }
-        @objects << {
-          :type => :collection,
-          :method_name => 'providers',
-          :values => @providers
-        }
-      end
-
-
-      # This method define collection of text elements inside REST model
-      # XML syntax: <addresses>
-      #               <address>127.0.0.1</address>
-      #               <address>127.0.0.2</address>
-      #             </addresses>
-      def add_addresses!(collection_name, values=[])
-        @objects << {
-          :type => :collection,
-          :method_name => collection_name.sanitize,
-          :values => values.collect { |v| { :address => v.text.strip, :type => v[:type] }}
-        }
-      end
-
-      # This method define collection of text elements inside REST model
-      # XML syntax: <addresses>
-      #               <address>127.0.0.1</address>
-      #               <address>127.0.0.2</address>
-      #             </addresses>
-      def add_collection!(collection_name, values=[])
-        @objects << {
-          :type => :collection,
-          :method_name => collection_name.sanitize,
-          :values => values
-        }
-      end
-
-      # Basic method hander. This define a way how value from property
-      # will be returned
-      def method_handler(m, args=[])
-        case m[:type]
-          when :link then return @client.send(m[:method_name].singularize, m[:id])
-          when :text then return m[:value]
-          when :property then return m[:property]
-          when :collection then return m[:values]
-          when :list then return m[:value].join(", ")
-          else raise NoHandlerForMethod
-        end
-      end
-
-      def method_missing(method_name, *args)
-        # First of all search throught array for method name
-        m = search_for_method(method_name)
-        if m.nil?
-          if method_name == :"valid_provider?"
-            return providers.any? { |p| p.keys.include? args.first.to_sym }
-          end
-          if method_name == :"valid_provider_url?"
-            return providers.any? { |p| !p.find { |k, v| v.find { |u| u[:url] == args.first } }.nil? }
-          end
-          super
-        else
-          # Call appropriate handler for method
-          method_handler(m, args)
-        end
-      end
-
-      # This method adds blobs to the blob_list property
-      # of a bucket
-      def add_blob!(blob_name)
-        if @blob_list.nil?
-          @blob_list = [blob_name]
-          @objects << {
-            :type => :list,
-            :method_name => "blob_list",
-            :value => @blob_list
-          }
-        else
-          @blob_list << blob_name
-          current = search_for_method('blob_list')
-          current[:value] = @blob_list
-        end
-      end
-
-      private
-
-      def search_for_method(name)
-        @objects.detect { |o| o[:method_name] == "#{name}" }
-      end
-
-    end
-
-    class ActionObject < BaseObject
-
-      def initialize(opts={}, &block)
-        super(opts)
-        @action_urls = opts[:action_urls] || []
-        @actions = []
-      end
-
-      # This trigger is called right after action.
-      # This method does nothing inside ActionObject
-      # but it can be redifined and used in meta-programming
-      def action_trigger(action)
-      end
-
-      def add_action_link!(id, link)
-        m = {
-          :type => :action_link,
-          :method_name => "#{link['rel'].sanitize}!",
-          :id => id,
-          :href => link['href'],
-          :rel => link['rel'].sanitize,
-          :method => link['method'].sanitize
-        }
-        @objects << m
-        @actions << [m[:rel], m[:href]]
-        @action_urls << m[:href]
-      end
-
-      def actions
-        @objects.inject([]) do |result, item|
-          result << [item[:rel], item[:href]] if item[:type].eql?(:action_link)
-          result
-        end
-      end
-
-      def action_urls
-        actions.collect { |a| a.last }
-      end
-
-      alias :base_method_handler :method_handler
-
-      # First call BaseObject method handler,
-      # then, if not method found try ActionObject handler
-      def method_handler(m, args=[])
-        begin
-          base_method_handler(m, args)
-        rescue NoHandlerForMethod
-          case m[:type]
-            when :action_link then do_action(m, args)
-            else raise NoHandlerForMethod
-          end
-        end
-      end
-
-      alias :original_method_missing :method_missing
-
-      def method_missing(name, *args)
-        if name.to_s =~ /^has_(\w+)\?$/
-          return actions.any? { |a| a[0] == $1 }
-        end
-        original_method_missing(name, args)
-      end
-
-      private
-
-      def do_action(m, args)
-        args = args.first || {}
-        method = m[:method].to_sym
-        @client.request(method,
-                        m[:href],
-                        method == :get ? args : {},
-                        method == :get ? {} : args)
-        action_trigger(m[:rel])
-      end
-
-    end
-
-    class StatefulObject < ActionObject
-      attr_reader :state
-
-      def initialize(opts={}, &block)
-        super(opts)
-        @state = opts[:initial_state] || ''
-        add_default_states!
-      end
-
-      def add_default_states!
-        @objects << {
-          :method_name => 'stopped?',
-          :type => :state,
-          :state => 'STOPPED'
-        }
-        @objects << {
-          :method_name => 'running?',
-          :type => :state,
-          :state => 'RUNNING'
-        }
-        @objects << {
-          :method_name => 'pending?',
-          :type => :state,
-          :state => 'PENDING'
-        }
-        @objects << {
-          :method_name => 'shutting_down?',
-          :type => :state,
-          :state => 'SHUTTING_DOWN'
-        }
-      end
-
-      def action_trigger(action)
-        # Refresh object state after action unless the object was destroyed
-        return if action.to_s == "destroy"
-        @new_state_object = @client.send(self.base_name, self.id)
-        @state = @new_state_object.state
-        self.update_actions!
-      end
-
-      def add_run_action!(id, link)
-        @objects << {
-          :method_name => 'run',
-          :type => :run,
-          :url => link,
-        }
-      end
-
-      alias :action_method_handler :method_handler
-
-      def method_handler(m, args=[])
-        begin
-          action_method_handler(m, args)
-        rescue NoHandlerForMethod
-          case m[:type]
-            when :state then evaluate_state(m[:state], @state)
-            when :run then run_command(m[:url][:href], args)
-            else raise NoHandlerForMethod
-          end
-        end
-      end
-
-#      private
-
-      def run_command(instance_url, args)
-        credentials = args[1]
-        params = {
-          :cmd => args[0],
-          :private_key => credentials[:pem] ? File.read(credentials[:pem]) : nil,
-        }
-        params.merge!({
-          :username => credentials[:username],
-          :password => credentials[:password]
-        }) if credentials[:username] and credentials[:password]
-        @client.request(:post, instance_url, {}, params) do |response|
-          output = Nokogiri::XML(response)
-          (output/'/instance/output').first.text
-        end
-      end
-
-      def evaluate_state(method_state, current_state)
-        method_state.eql?(current_state)
-      end
-
-      def action_objects
-        @objects.select { |o| o[:type] == :action_link }
-      end
-
-      def update_actions!
-        new_actions = @new_state_object.action_objects
-        @objects.reject! { |o| o[:type] == :action_link }
-        @objects = (@objects + new_actions)
-      end
-
-    end
-
-    def self.add_class(name, parent=:base)
-      parent = parent.to_s
-      parent_class = "#{parent.classify}Object"
-      @defined_classes ||= []
-      class_name = "#{parent.classify}::#{name.classify}"
-      unless @defined_classes.include?(class_name)
-        DeltaCloud::API.class_eval("class #{class_name} < DeltaCloud::#{parent_class}; end")
-        @defined_classes << class_name
-      end
-
-      DeltaCloud::API.const_get(parent.classify).const_get(name.classify)
-    end
-
-    def self.guess_model_type(response)
-      response = Nokogiri::XML(response.to_s)
-      return :action if ((response/'//actions').length >= 1) and ((response/'//state').length == 0)
-      return :stateful if ((response/'//actions').length >= 1) and ((response/'//state').length >= 1)
-      return :base
-    end
-
-    class API
-      class Action; end
-      class Base; end
-      class Stateful; end
-    end
-end
diff --git a/client/lib/client_bucket_methods.rb b/client/lib/client_bucket_methods.rb
deleted file mode 100644
index a3dfda0..0000000
--- a/client/lib/client_bucket_methods.rb
+++ /dev/null
@@ -1,69 +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 ClientBucketMethods
-
-  def create_bucket(params)
-    obj = nil
-    request(:post, "#{api_uri.to_s}/buckets", {:name => params['id'],:location=>params['bucket_location'] }) do |response|
-      handle_backend_error(response) if response.code!=201
-      obj = base_object(:bucket, response)
-    end
-  end
-
-  def destroy_bucket(params)
-    #actually response here is 204 - no content - so nothing returned to client?
-    request(:delete, "#{api_uri.to_s}/buckets/#{params['id']}") do |response|
-      handle_backend_error(response) if response.code!=204
-      nil if response.code == 204
-    end
-  end
-
-  def create_blob(params)
-    blob = nil
-    resource = RestClient::Resource.new("#{api_uri.to_s}/buckets/#{params['bucket']}", :open_timeout => 10, :timeout => 45)
-    headers = default_headers.merge(extended_headers)
-    unless params['metadata'].nil?
-      metadata_headers = {}
-      params['metadata'].each   do |k,v|
-        metadata_headers["X-Deltacloud-Blobmeta-#{k}"] = v
-      end
-      headers = headers.merge(metadata_headers)
-    end
-    resource.send(:post, {:blob_data => File.new(params['file_path'], 'rb'), :blob_id => params[:id]}, headers) do |response, request, block|
-      handle_backend_error(response) if response.code.eql?(500)
-      blob = base_object(:blob, response)
-      yield blob if block_given?
-    end
-    return blob
-  end
-
-  def destroy_blob(params)
-    request(:delete, "#{api_uri.to_s}/buckets/#{params['bucket']}/#{params[:id]}") do |response|
-      handle_backend_error(response) if response.code!=204
-      nil if response.code == 204
-    end
-  end
-
-  #RestClient doesn't do streaming 'get' yet - we already opened a pull request on this see
-  #https://github.com/archiloque/rest-client/issues/closed#issue/62 - apparently its going to
-  #be in the next version - unknown when. For now get full response. FIXME
-  def blob_data(params)
-    request(:get, "#{api_uri.to_s}/buckets/#{params['bucket']}/#{params[:id]}/content") do |response|
-      response
-    end
-  end
-
-end
diff --git a/client/lib/deltacloud.rb b/client/lib/deltacloud.rb
deleted file mode 100644
index a58c280..0000000
--- a/client/lib/deltacloud.rb
+++ /dev/null
@@ -1,486 +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 'nokogiri'
-require 'rest_client'
-require 'base64'
-require 'logger'
-require 'require_relative' if RUBY_VERSION =~ /^1\.8/
-require_relative './hwp_properties.rb'
-require_relative './instance_state.rb'
-require_relative './documentation.rb'
-require_relative './base_object.rb'
-require_relative './errors.rb'
-require_relative './client_bucket_methods.rb'
-
-module DeltaCloud
-
-  # Get a new API client instance
-  #
-  # @param [String, user_name] API user name
-  # @param [String, password] API password
-  # @param [String, url] API URL (eg. http://localhost:3001/api)
-  # @return [DeltaCloud::API]
-  #def self.new(user_name, password, api_url, opts={}, &block)
-  #  opts ||= {}
-  #  API.new(user_name, password, api_url, opts, &block)
-  #end
-
-  def self.new(user_name, password, api_url, &block)
-    API.new(user_name, password, api_url, &block)
-  end
-
-  # Check given credentials if their are valid against
-  # backend cloud provider
-  #
-  # @param [String, user_name] API user name
-  # @param [String, password] API password
-  # @param [String, user_name] API URL (eg. http://localhost:3001/api)
-  # @return [true|false]
-  def self.valid_credentials?(user_name, password, api_url, opts={})
-    api=API.new(user_name, password, api_url, opts)
-    result = false
-    api.request(:get, '', :force_auth => '1') do |response|
-      result = true if response.code.eql?(200)
-    end
-    return result
-  end
-
-  # Return a API driver for specified URL
-  #
-  # @param [String, url] API URL (eg. http://localhost:3001/api)
-  def self.driver_name(url)
-    API.new(nil, nil, url).driver_name
-  end
-
-  class API
-    attr_reader :api_uri, :driver_name, :api_version, :features, :entry_points
-    attr_reader :api_driver, :api_provider
-
-    def initialize(user_name, password, api_url, opts={}, &block)
-      opts[:version] = true
-      @api_driver, @api_provider = opts[:driver], opts[:provider]
-      @username, @password = opts[:username] || user_name, opts[:password] || password
-      @api_uri = URI.parse(api_url)
-      @features, @entry_points = {}, {}
-      @verbose = opts[:verbose] || false
-      discover_entry_points
-      if entry_points.include?(:buckets)
-        extend(ClientBucketMethods)
-      end
-      yield self if block_given?
-    end
-
-    # This method can be used to switch back-end cloud
-    # for API instance using HTTP headers.
-    # Options must include:
-    # {
-    #   :driver => 'rhevm|ec2|gogrid|...',
-    #   :username => 'API key for backend',
-    #   :password => 'API secret key for backend',
-    # }
-    # Optionally you can pass also :provider option to change
-    # provider entry-point
-    #
-    # Example usage:
-    # client = Deltacloud::new('url', 'username', 'password')
-    # ...
-    # client.with_config(:driver => 'ec2', :username => '', :password => '') do |ec2|
-    #   ec2.realms
-    # end
-    #
-    # Note: After this block finish client instance will be set back to default
-    # state
-    #
-    # @param [Hash, opts] New provider configuration
-    def with_config(opts, &block)
-      api_instance = self.dup
-      api_instance.use_driver(opts[:driver],
-                             :username => opts[:username],
-                             :password => opts[:password],
-                             :provider => opts[:provider])
-      yield api_instance if block_given?
-      api_instance
-    end
-
-    def connect(&block)
-      yield self
-    end
-
-    # Return API hostname
-    def api_host; @api_uri.host ; end
-
-    # Return API port
-    def api_port; @api_uri.port ; end
-
-    # Return API path
-    def api_path; @api_uri.path ; end
-
-    # Define methods based on 'rel' attribute in entry point
-    # Two methods are declared: 'images' and 'image'
-    def declare_entry_points_methods(entry_points)
-      API.instance_eval do
-        entry_points.keys.select {|k| [:instance_states].include?(k)==false }.each do |model|
-
-          define_method model do |*args|
-            request(:get, entry_points[model], args.first) do |response|
-              base_object_collection(model, response)
-            end
-          end
-
-          define_method :"#{model.to_s.singularize}" do |*args|
-            request(:get, "#{entry_points[model]}/#{args[0]}") do |response|
-              base_object(model, response)
-            end
-          end
-
-          define_method :"fetch_#{model.to_s.singularize}" do |url|
-            url =~ /\/#{model}\/(.*)$/
-            self.send(model.to_s.singularize.to_sym, $1)
-          end
-
-      end
-
-      #define methods for blobs:
-      if(entry_points.include?(:buckets))
-        define_method :"blob" do |*args|
-            bucket = args[0]["bucket"]
-            blob = args[0][:id]
-            request(:get, "#{entry_points[:buckets]}/#{bucket}/#{blob}") do |response|
-              base_object("blob", response)
-            end
-        end
-      end
-
-      end
-    end
-
-    def base_object_collection(model, response)
-      Nokogiri::XML(response).xpath("#{model}/#{model.to_s.singularize}").collect do |item|
-        base_object(model, item.to_s)
-      end
-    end
-
-    # Add default attributes [id and href] to class
-    def base_object(model, response)
-      c = DeltaCloud.add_class("#{model}", DeltaCloud::guess_model_type(response))
-      xml_to_class(c, Nokogiri::XML(response).xpath("#{model.to_s.singularize}").first)
-    end
-
-    # Convert XML response to defined Ruby Class
-    def xml_to_class(base_object, item)
-
-      return nil unless item
-
-      params = {
-          :id => item['id'],
-          :url => item['href'],
-          :name => item.name,
-          :client => self
-      }
-      params.merge!({ :initial_state => (item/'state').text.sanitize }) if (item/'state').length > 0
-
-      obj = base_object.new(params)
-      # Traverse across XML document and deal with elements
-      item.xpath('./*').each do |attribute|
-        # Do a link for elements which are links to other REST models
-        if self.entry_points.keys.include?(:"#{attribute.name}s")
-          obj.add_link!(attribute.name, attribute['id']) && next unless (attribute.name == 'bucket' && item.name == 'blob')
-        end
-
-        # Do a HWP property for hardware profile properties
-        if attribute.name == 'property'
-          if attribute['value'] =~ /^(\d+)\.(\d+)$/
-            obj.add_hwp_property!(attribute['name'], attribute, :float) && next
-          else
-            obj.add_hwp_property!(attribute['name'], attribute, :integer) && next
-          end
-        end
-
-        # If there are actions, add they to ActionObject/StateFullObject
-        if attribute.name == 'actions'
-          (attribute/'link').each do |link|
-            (obj.add_run_action!(item['id'], link) && next) if link[:rel] == 'run'
-            obj.add_action_link!(item['id'], link)
-          end && next
-        end
-
-        if attribute.name == 'mount'
-          obj.add_link!("instance", (attribute/"./instance/@id").first.value)
-          obj.add_text!("device", (attribute/"./device/@name").first.value)
-          next
-        end
-
-        #deal with blob metadata
-        if (attribute.name == 'user_metadata')
-          meta = {}
-          attribute.children.select {|x| x.name=="entry" }.each  do |element|
-            value = element.content.gsub!(/(\n) +/,'')
-            meta[element['key']] = value
-          end
-          obj.add_collection!(attribute.name, meta.inspect) && next
-        end
-
-        if (['public_addresses', 'private_addresses'].include? attribute.name)
-          obj.add_addresses!(attribute.name, (attribute/'*')) && next
-        end
-
-        if ('authentication'.include? attribute.name)
-          obj.add_authentication!(attribute[:type], (attribute/'*')) && next
-        end
-
-        #deal with providers
-        if(attribute.name == 'provider')
-          obj.add_provider!(attribute.attributes['id'].value, (attribute/'entrypoint')) && next
-        end
-
-        # Deal with collections like public-addresses, private-addresses
-        if (attribute/'./*').length > 0
-          obj.add_collection!(attribute.name, (attribute/'*').collect { |value| value.text }) && next
-        end
-
-        #deal with blobs for buckets
-        if(attribute.name == 'blob')
-          obj.add_blob!(attribute.attributes['id'].value) && next
-        end
-
-        # Anything else is treaten as text object
-        obj.add_text!(attribute.name, attribute.text.convert)
-      end
-      return obj
-    end
-
-    # Get /api and parse entry points
-    def discover_entry_points
-      return if discovered?
-      request(:get, @api_uri.to_s) do |response|
-        if response.code == 301
-          @api_uri = response.headers[:location]
-          return discover_entry_points
-        end
-        api_xml = Nokogiri::XML(response)
-        @driver_name = api_xml.xpath('/api').first[:driver]
-        @api_version = api_xml.xpath('/api').first[:version]
-
-        api_xml.css("api > link").each do |entry_point|
-          rel, href = entry_point['rel'].to_sym, entry_point['href']
-          @entry_points.store(rel, href)
-
-          entry_point.css("feature").each do |feature|
-            @features[rel] ||= []
-            @features[rel] << feature['name'].to_sym
-
-          end
-        end
-      end
-      declare_entry_points_methods(@entry_points)
-    end
-
-    # Generate create_* methods dynamically
-    #
-    def method_missing(name, *args)
-      if name.to_s =~ /^([\w_]+)_ids$/
-        return self.send(:"#{$1.pluralize}").map { |o| o.id }
-      end
-      if name.to_s =~ /^create_(\w+)/
-        params = args[0] if args[0] and args[0].class.eql?(Hash)
-        params ||= args[1] if args[1] and args[1].class.eql?(Hash)
-        params ||= {}
-
-        # FIXME: This fixes are related to Instance model and should be
-        # replaced by 'native' parameter names
-
-        params[:realm_id] ||= params[:realm] if params[:realm]
-        params[:keyname] ||= params[:key_name] if params[:key_name]
-        params[:user_data] = Base64::encode64(params[:user_data]) if params[:user_data]
-
-        if params[:hardware_profile] and params[:hardware_profile].class.eql?(Hash)
-          params[:hardware_profile].each do |k,v|
-            params[:"hwp_#{k}"] ||= v
-          end
-        else
-          params[:hwp_id] ||= params[:hardware_profile]
-        end
-
-        params[:image_id] ||= params[:image_id] || args[0] if args[0].class!=Hash
-
-        obj = nil
-
-        request(:post, entry_points[:"#{$1}s"], {}, params) do |response|
-          obj = base_object(:"#{$1}", response)
-          response_error(response) unless response_successful?(response.code)
-          yield obj if block_given?
-        end
-        return obj
-      end
-      raise NoMethodError
-    end
-
-    def use_driver(driver, opts={})
-      if driver
-        @api_driver = driver
-        @driver_name = driver
-        @api_provider = opts[:provider] if opts[:provider]
-        @features, @entry_points = {}, {}
-        discover_entry_points
-      end
-      @username = opts[:username] if opts[:username]
-      @password = opts[:password] if opts[:password]
-      @api_provider = opts[:provider] if opts[:provider]
-      return self
-    end
-
-    def use_config!(opts={})
-      @api_uri = URI.parse(opts[:url]) if opts[:url]
-      use_driver(opts[:driver], opts)
-    end
-
-    def extended_headers
-      headers = {}
-      headers["X-Deltacloud-Driver"] = @api_driver.to_s if @api_driver
-      headers["X-Deltacloud-Provider"] = @api_provider.to_s if @api_provider
-      headers
-    end
-
-    def response_successful?(code)
-      return true if code.to_s =~ /^2(\d{2})$/
-      return true if code.to_s =~ /^3(\d{2})$/
-      return false
-    end
-
-    def response_error(response)
-      xml = Nokogiri::XML(response.to_s)
-      if (xml/'message').empty? and response.code.to_s =~ /4(\d{2})/
-        DeltaCloud::HTTPError.client_error(response.code)
-      else
-        opts = {
-          :params => (xml/'request/param').inject({}) { |r,p| r[:"#{p[:name]}"] = p.text; r }
-        }
-        if backend_node = xml.at_xpath('/error/backend')
-          opts[:driver]   = backend_node[:driver]
-          opts[:provider] = backend_node[:provider]
-        end
-        backtrace = (xml/'backtrace').empty? ? nil : (xml/'backtrace').first.text.split("\n")[1..10].map { |l| l.strip }
-        DeltaCloud::HTTPError.server_error(xml.root[:status] || response.code,
-                                           (xml/'message').first.text, opts, backtrace)
-      end
-    end
-
-    # Basic request method
-    #
-    def request(*args, &block)
-      conf = {
-        :method => (args[0] || 'get').to_sym,
-        :path => (args[1]=~/^http/) ? args[1] : "#{api_uri.to_s}#{args[1]}",
-        :query_args => args[2] || {},
-        :form_data => args[3] || {},
-        :timeout => args[4] || 45,
-        :open_timeout => args[5] || 10
-      }
-      if conf[:query_args] != {}
-        conf[:path] += '?' + URI.escape(conf[:query_args].collect{ |key, value| "#{key}=#{value}" }.join('&')).to_s
-      end
-
-      if conf[:method].eql?(:post)
-        resource = RestClient::Resource.new(conf[:path], :open_timeout => conf[:open_timeout], :timeout => conf[:timeout])
-        resource.send(:post, conf[:form_data], default_headers.merge(extended_headers)) do |response, request, block|
-          response_error(response) unless response_successful? response.code
-          yield response.to_s if block_given?
-        end
-      else
-        resource = RestClient::Resource.new(conf[:path], :open_timeout => conf[:open_timeout], :timeout => conf[:timeout])
-        resource.send(conf[:method], default_headers.merge(extended_headers)) do |response, request, block|
-          response_error(response) unless response_successful? response.code
-          yield response.to_s if block_given?
-        end
-      end
-    end
-
-
-    # Check if specified collection have wanted feature
-    def feature?(collection, name)
-      @features.has_key?(collection) && @features[collection].include?(name)
-    end
-
-    # List available instance states and transitions between them
-    def instance_states
-      states = []
-      request(:get, entry_points[:instance_states]) do |response|
-        Nokogiri::XML(response).xpath('states/state').each do |state_el|
-          state = DeltaCloud::InstanceState::State.new(state_el['name'])
-          state_el.xpath('transition').each do |transition_el|
-            state.transitions << DeltaCloud::InstanceState::Transition.new(
-              transition_el['to'],
-              transition_el['action']
-            )
-          end
-          states << state
-        end
-      end
-      states
-    end
-
-    # Select instance state specified by name
-    def instance_state(name)
-      instance_states.select { |s| s.name.to_s.eql?(name.to_s) }.first
-    end
-
-    # Skip parsing /api when we already got entry points
-    def discovered?
-      true if @entry_points!={}
-    end
-
-    # This method will retrieve API documentation for given collection
-    def documentation(collection, operation=nil)
-      data = {}
-      request(:get, "/docs/#{collection}") do |body|
-        document = Nokogiri::XML(body)
-        if operation
-          data[:operation] = operation
-          data[:description] = document.xpath('/docs/collection/operations/operation[@name = "'+operation+'"]/description').first.text.strip
-          return false unless data[:description]
-          data[:params] = []
-          (document/"/docs/collection/operations/operation[@name='#{operation}']/parameter").each do |param|
-            data[:params] << {
-              :name => param['name'],
-              :required => param['type'] == 'optional',
-              :type => (param/'class').text
-            }
-          end
-        else
-          data[:description] = (document/'/docs/collection/description').text
-          data[:collection] = collection
-          data[:operations] = (document/"/docs/collection/operations/operation").collect{ |o| o['name'] }
-        end
-      end
-      return Documentation.new(self, data)
-    end
-
-    private
-
-    def default_headers
-      # The linebreaks inserted every 60 characters in the Base64
-      # encoded header cause problems under JRuby
-      auth_header = "Basic "+Base64.encode64("#{@username}:#{@password}")
-      auth_header.gsub!("\n", "")
-      {
-        :authorization => auth_header,
-        :accept => "application/xml"
-      }
-    end
-
-  end
-
-end
diff --git a/client/lib/deltacloud/client.rb b/client/lib/deltacloud/client.rb
new file mode 100644
index 0000000..36200ad
--- /dev/null
+++ b/client/lib/deltacloud/client.rb
@@ -0,0 +1,78 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 Client
+    require 'require_relative' if RUBY_VERSION < '1.9'
+    require 'ostruct'
+    require 'nokogiri'
+    require 'faraday'
+
+    # Core extensions
+    require_relative './core_ext'
+
+    # Errors && Helpers
+    require_relative './client/helpers/model_helper'
+    require_relative './client/helpers/xml_helper'
+    require_relative './client/helpers/property_helper'
+
+    # Exceptions goes here
+    require_relative './client/base_error'
+
+    # Faraday Middleware for Deltacloud errors
+    require_relative './error_response'
+
+    # Deltacloud API methods
+    require_relative './client/methods/api'
+    require_relative './client/methods/backward_compatiblity'
+
+    # Extend Client module with methods that existed in old client
+    # and we want to keep them.
+    # Deprecation warnings should be provided to users if they use something
+    # from these modules.
+    #
+    extend Deltacloud::Client::Methods::BackwardCompatibility::ClassMethods
+
+    # Deltacloud methods
+    require_relative './client/methods'
+
+    # Deltacloud models
+    require_relative './client/models'
+
+    require_relative './client/connection'
+
+    VERSION = '1.1.2'
+
+    # Check if the connection to Deltacloud API is valid
+    def self.valid_connection?(api_url)
+      begin
+        Deltacloud::Client(api_url, '', '') && true
+      rescue Faraday::Error::ConnectionFailed
+        false
+      rescue Deltacloud::Client::AuthenticationError
+        false
+      end
+    end
+
+  end
+
+  def self.Client(url, api_user, api_password, opts={})
+    Client::Connection.new({
+      :url => url,
+      :api_user => api_user,
+      :api_password => api_password
+    }.merge(opts))
+  end
+end
diff --git a/client/lib/deltacloud/client/base_error.rb b/client/lib/deltacloud/client/base_error.rb
new file mode 100644
index 0000000..544aa90
--- /dev/null
+++ b/client/lib/deltacloud/client/base_error.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.
+
+module Deltacloud::Client
+
+  # Reporting internal client errors
+  #
+  class Error < StandardError; end
+
+  class BaseError < Error
+    attr_reader :server_backtrace
+    attr_reader :driver
+    attr_reader :provider
+    attr_reader :status
+
+    def initialize(opts={})
+      if opts.is_a? Hash
+        @server_backtrace = opts[:server_backtrace]
+        @driver = opts[:driver]
+        @provider = opts[:provider]
+        @status = opts[:status]
+        @original_error = opts[:original_error]
+        super(opts[:message])
+      else
+        super(opts)
+      end
+    end
+
+    # Return the original XML error message received from Deltacloud API
+    def original_error
+      @original_error
+    end
+
+    # If the Deltacloud API server error response contain backtrace from
+    # server,then make this backtrace available as part of this exception
+    # backtrace
+    #
+    def set_backtrace(backtrace)
+      return super(backtrace) if @server_backtrace.nil?
+      super([
+        backtrace[0..3],
+        "-------Deltacloud API backtrace-------",
+        @server_backtrace.split[0..10],
+      ].flatten)
+    end
+
+  end
+
+  # Report 401 errors
+  class AuthenticationError < BaseError; end
+
+  # Report 502 errors (back-end cloud provider encounter error)
+  class BackendError < BaseError; end
+
+  # Report 5xx errors (error on Deltacloud API server)
+  class ServerError < BaseError; end
+
+  # Report 501 errors (collection or operation is not supported)
+  class NotSupported < ServerError; end
+
+  # Report 4xx failures (client failures)
+  class ClientFailure < BaseError; end
+
+  # Report 404 error (object not found)
+  class NotFound < BaseError; end
+
+  # Report 405 failures (resource state does not permit the requested operation)
+  class InvalidState < ClientFailure; end
+
+  # Report this when client do Image#launch using incompatible HWP
+  class IncompatibleHardwareProfile < ClientFailure; end
+end
diff --git a/client/lib/deltacloud/client/connection.rb b/client/lib/deltacloud/client/connection.rb
new file mode 100644
index 0000000..ad91cb0
--- /dev/null
+++ b/client/lib/deltacloud/client/connection.rb
@@ -0,0 +1,135 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class Connection
+
+    attr_accessor :connection
+    attr_reader :request_driver
+    attr_reader :request_provider
+    attr_reader :entrypoint
+
+    include Deltacloud::Client::Helpers::Model
+
+    include Deltacloud::Client::Methods::Common
+    include Deltacloud::Client::Methods::Api
+    include Deltacloud::Client::Methods::BackwardCompatibility
+    include Deltacloud::Client::Methods::Driver
+    include Deltacloud::Client::Methods::Realm
+    include Deltacloud::Client::Methods::HardwareProfile
+    include Deltacloud::Client::Methods::Image
+    include Deltacloud::Client::Methods::Instance
+    include Deltacloud::Client::Methods::InstanceState
+    include Deltacloud::Client::Methods::Key
+    include Deltacloud::Client::Methods::StorageVolume
+    include Deltacloud::Client::Methods::StorageSnapshot
+    include Deltacloud::Client::Methods::Address
+    include Deltacloud::Client::Methods::Bucket
+    include Deltacloud::Client::Methods::Blob
+    include Deltacloud::Client::Methods::Firewall
+
+    def initialize(opts={})
+      @request_driver = opts[:driver]
+      @request_provider = opts[:provider]
+      @connection = Faraday.new(:url => opts[:url]) do |f|
+        # NOTE: The order of this is somehow important for VCR
+        #       recording.
+        f.request :url_encoded
+        f.headers = deltacloud_request_headers
+        f.basic_auth opts[:api_user], opts[:api_password]
+        f.use Deltacloud::ErrorResponse
+        f.adapter :net_http
+      end
+      cache_entrypoint!
+      @request_driver ||= current_driver
+      @request_provider ||= current_provider
+    end
+
+    # Change the current driver and return copy of the client
+    # This allows chained calls like: client.driver(:ec2).instances
+    #
+    # - driver_id -> The new driver id (:mock, :ec2, :rhevm, ...)
+    # - api_user -> API user name
+    # - api_password -> API password
+    # - api_provider -> API provider (aka API_PROVIDER string)
+    #
+    def use(driver_id, api_user, api_password, api_provider=nil, &block)
+      new_client = self.class.new(
+        :url => @connection.url_prefix.to_s,
+        :api_user => api_user,
+        :api_password => api_password,
+        :provider => api_provider,
+        :driver => driver_id
+      )
+      new_client.cache_entrypoint!
+      yield new_client if block_given?
+      new_client
+    end
+
+    # Change the API provider but keep the current client credentials.
+    # This allows to change the EC2 region and list instances in that
+    # region without need to supply credentials.
+    #
+    # client.use_provider('eu-west-1') { |p| p.instances }
+    #
+    # - provider_id -> API provider (aka API_PROVIDER)
+    #
+    def use_provider(provider_id, &block)
+      new_client = self.clone
+      new_connection = @connection.clone
+      new_connection.headers['X-Deltacloud-Provider'] = provider_id
+      new_client.connection = new_connection
+      new_client.cache_entrypoint!(true)
+      yield new_client if block_given?
+      new_client
+    end
+
+    # Cache the API entrypoint (/api) for the current connection,
+    # so we don't need to query /api everytime we ask if certain
+    # collection/operation is supported
+    #
+    # - force -> If 'true' force to refresh stored cached entrypoint
+    #
+    def cache_entrypoint!(force=false)
+      @entrypoint = nil if force
+      @entrypoint ||= connection.get(path).body
+    end
+
+    # Check if the credentials used are valid for the current @connection
+    #
+    def valid_credentials?
+      begin
+        r = connection.get(path, { :force_auth => 'true' })
+        r.status == 200
+      rescue error(:authentication_error)
+        false
+      end
+    end
+
+    private
+
+    # Default Deltacloud HTTP headers. Common for *all* requests
+    # to Deltacloud API
+    #
+    def deltacloud_request_headers
+      headers = {}
+      headers['Accept'] = 'application/xml'
+      headers['X-Deltacloud-Driver'] = @request_driver.to_s if @request_driver
+      headers['X-Deltacloud-Provider'] = @request_provider.to_s if @request_provider
+      headers
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/client/helpers/model_helper.rb b/client/lib/deltacloud/client/helpers/model_helper.rb
new file mode 100644
index 0000000..2224d0d
--- /dev/null
+++ b/client/lib/deltacloud/client/helpers/model_helper.rb
@@ -0,0 +1,69 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Helpers
+    module Model
+
+      # Retrieve the class straight from
+      # Deltacloud::Client model.
+      #
+      # -name -> A class name in underscore form (:storage_volume)
+      #
+      def model(name)
+        if name.nil? or (!name.nil? and name.empty?)
+          raise error.new("The model name can't be blank")
+        end
+        Deltacloud::Client.const_get(name.to_s.camelize)
+      end
+
+      # Syntax sugar method for retrieving various Client
+      # exception classes.
+      #
+      # - name -> Exception class name in underscore
+      #
+      # NOTE: If name is 'nil' the default Error exception
+      #       will be returned
+      #
+      def error(name=nil)
+        model(name || :error)
+      end
+
+      # Checks if current @connection support +model_name+
+      # and then convert HTTP response to a Ruby model
+      #
+      # - model_name -> A class name in underscore form
+      # - collection_body -> HTTP body of collection
+      #
+      def from_collection(model_name, collection_body)
+        must_support!(model_name)
+        model(model_name.to_s.singularize).from_collection(
+          self,
+          collection_body
+        )
+      end
+
+      # Check if the collection for given model is supported
+      # in current @connection and then parse/convert
+      # resource XML to a Ruby class
+      #
+      def from_resource(model_name, resource_body)
+        must_support!(model_name.to_s.pluralize)
+        model(model_name).convert(self, resource_body)
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/helpers/property_helper.rb b/client/lib/deltacloud/client/helpers/property_helper.rb
new file mode 100644
index 0000000..a30ab9a
--- /dev/null
+++ b/client/lib/deltacloud/client/helpers/property_helper.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::Client
+  module Helpers
+    module Property
+
+      class Property
+        attr_reader :name, :unit, :default
+
+        def initialize(name, unit, default=nil)
+          @name = name
+          @unit = unit
+          @default = default
+        end
+
+        def value
+          @default || 'opaque'
+        end
+
+        def self.parse(body)
+          Property.new(body['name'], body['unit'], body['value'])
+        end
+
+        def kind
+          self.class.name.split('::').last.downcase.to_sym
+        end
+
+      end
+
+      class Range < Property
+
+        attr_reader :first, :last
+
+        def initialize(name, unit, first, last, default=nil)
+          @first, @last = first, last
+          super(name, unit, default)
+        end
+
+        def value
+          ::Range.new(@first.to_i, @last.to_i)
+        end
+
+        def self.parse(body)
+          base = super
+          new(base.name, base.unit, body.at('range')['first'], body.at('range')['last'], base.default)
+        end
+
+      end
+
+      class Enum < Property
+        include Enumerable
+        attr_reader :values
+
+        def initialize(name, unit, values, default=nil)
+          @values = values
+          super(name, unit, default)
+        end
+
+        def value
+          @values
+        end
+
+        def each
+          value.each
+        end
+
+        def self.parse(body)
+          base = super
+          new(base.name, base.unit, body.xpath('enum/entry').map { |e| e['value'] }, base.default)
+        end
+      end
+
+      class Fixed < Property
+        attr_reader :value
+
+        def initialize(name, unit, value)
+          @value = value
+          super(name, unit, @value)
+        end
+
+        def self.parse(body)
+          base = super
+          new(base.name, base.unit, body['value'])
+        end
+
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/helpers/xml_helper.rb b/client/lib/deltacloud/client/helpers/xml_helper.rb
new file mode 100644
index 0000000..5874c00
--- /dev/null
+++ b/client/lib/deltacloud/client/helpers/xml_helper.rb
@@ -0,0 +1,33 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Helpers
+    module XmlHelper
+
+      # Extract XML string from the various objects
+      #
+      def extract_xml_body(obj)
+        case obj
+        when Faraday::Response then obj.body
+        when Nokogiri::XML::Element then obj.to_s
+        when Nokogiri::XML::Document then obj.to_s
+        else obj
+        end
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods.rb b/client/lib/deltacloud/client/methods.rb
new file mode 100644
index 0000000..0897866
--- /dev/null
+++ b/client/lib/deltacloud/client/methods.rb
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 './methods/common'
+require_relative './methods/driver'
+require_relative './methods/realm'
+require_relative './methods/hardware_profile'
+require_relative './methods/image'
+require_relative './methods/instance'
+require_relative './methods/instance_state'
+require_relative './methods/storage_volume'
+require_relative './methods/storage_snapshot'
+require_relative './methods/key'
+require_relative './methods/address'
+require_relative './methods/bucket'
+require_relative './methods/blob'
+require_relative './methods/firewall'
diff --git a/client/lib/deltacloud/client/methods/address.rb b/client/lib/deltacloud/client/methods/address.rb
new file mode 100644
index 0000000..21da5f6
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/address.rb
@@ -0,0 +1,68 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Client
+  module Methods
+    module Address
+
+      # Retrieve list of all address entities
+      #
+      # Filter options:
+      #
+      # - :id -> Filter entities using 'id' attribute
+      #
+      def addresses(filter_opts={})
+        from_collection :addresses,
+        connection.get(api_uri('addresses'), filter_opts)
+      end
+
+      # Retrieve the single address entity
+      #
+      # - address_id -> Address entity to retrieve
+      #
+      def address(address_id)
+        from_resource :address,
+          connection.get(api_uri("addresses/#{address_id}"))
+      end
+
+      # Create a new address
+      #
+      def create_address
+        create_resource :address, {}
+      end
+
+      def destroy_address(address_id)
+        destroy_resource :address, address_id
+      end
+
+      def associate_address(address_id, instance_id)
+        result = connection.post(
+          api_uri("/addresses/#{address_id}/associate")
+        ) do |request|
+          request.params = { :instance_id => instance_id }
+        end
+        result.status == 202
+      end
+
+      def disassociate_address(address_id)
+        result = connection.post(
+          api_uri("/addresses/#{address_id}/disassociate")
+        )
+        result.status == 202
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/api.rb b/client/lib/deltacloud/client/methods/api.rb
new file mode 100644
index 0000000..32bd048
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/api.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 Deltacloud::Client
+  module Methods
+    module Api
+
+      def path
+        connection.url_prefix.path
+      end
+
+      def api_uri(uri)
+        URI.parse([path, uri.gsub(/^(\/+)/,'')].join('/'))
+      end
+
+      # The current version of Deltacloud API
+      #
+      def version
+        entrypoint.to_xml.root['version']
+      end
+
+      alias_method :api_version, :version
+
+      # The current driver the @connection is using
+      #
+      def current_driver
+        entrypoint.to_xml.root['driver']
+      end
+
+      alias_method :api_driver,   :current_driver
+      alias_method :driver_name,  :current_driver
+
+      # The current provider the @connection is using
+      #
+      def current_provider
+        entrypoint.to_xml.root['provider']
+      end
+
+      # List of the currently supported collections by @connection
+      #
+      def supported_collections
+        entrypoint.to_xml.root.xpath('link').map { |l| l['rel'] }
+      end
+
+      alias_method :entrypoints, :supported_collections
+
+      # Syntax sugar for +supported_collections+
+      # Return 'true' if the collection is supported by current API entrypoint
+      #
+      def support?(collection)
+        supported_collections.include? collection.to_s
+      end
+
+      # Syntax sugar for Method modules, where you can 'require' the support
+      # for the given collection before you execute API call
+      #
+      # Raise +NotSupported+ exception if the given +collection+ is not
+      # supported
+      #
+      def must_support!(collection)
+        unless support?(collection)
+          raise error(:not_supported).new("Collection '#{collection}' not supported by current API endpoint.")
+        end
+      end
+
+      # +Hash+ of all features supported by current connection
+      #
+      def features
+        entrypoint.to_xml.root.xpath('link/feature').inject(Hash.new(Array.new)) do |result, feature|
+          result[feature.parent['rel']] += [feature['name']]
+          result
+        end
+      end
+
+      # Check if the current collection support given feature for given
+      # collection
+      #
+      def feature?(collection_name, feature_name)
+        features[collection_name.to_s].include?(feature_name.to_s)
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/backward_compatiblity.rb b/client/lib/deltacloud/client/methods/backward_compatiblity.rb
new file mode 100644
index 0000000..8718836
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/backward_compatiblity.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.
+
+module Deltacloud::Client
+  module Methods
+    module BackwardCompatibility
+
+      # Backward compatibility methods provides fallback for the
+      # old deltacloud-client gem.
+      #
+      #
+      def api_host
+        connection.url_prefix.host
+      end
+
+      def api_port
+        connection.url_prefix.port
+      end
+
+      def connect(&block)
+        yield self.clone
+      end
+
+      def with_config(opts, &block)
+        yield inst = use(
+          opts[:driver],
+          opts[:username],
+          opts[:password],
+          opts[:provider]
+        ) if block_given?
+        inst
+      end
+
+      def use_driver(new_driver, opts={})
+        with_config(opts.merge(:driver => new_driver))
+      end
+
+      alias_method :"use_config!", :use_driver
+
+      def discovered?
+        true unless entrypoint.nil?
+      end
+
+      module ClassMethods
+
+        def valid_credentials?(api_user, api_password, api_url, opts={})
+          args = {
+            :api_user => api_user,
+            :api_password => api_password,
+            :url => api_url
+          }
+          args.merge!(:providers => opts[:provider]) if opts[:provider]
+          Deltacloud::Client::Connection.new(args).valid_credentials?
+        end
+
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/blob.rb b/client/lib/deltacloud/client/methods/blob.rb
new file mode 100644
index 0000000..80a3945
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/blob.rb
@@ -0,0 +1,91 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module Blob
+
+      # Retrieve list of all blob entities from given bucket
+      #
+      def blobs(bucket_id=nil)
+        raise error.new("The :bucket_id cannot be nil.") if bucket_id.nil?
+        bucket(bucket_id).blob_ids.map { |blob_id| blob(bucket_id, blob_id) }
+      end
+
+      # Retrieve the single blob entity
+      #
+      # - blob_id -> Blob entity to retrieve
+      #
+      def blob(bucket_id, blob_id)
+        model(:blob).convert(
+          self,
+          connection.get(api_uri("buckets/#{bucket_id}/#{blob_id}"))
+        )
+      end
+
+      # Create a new blob
+      #
+      # - bucket_id -> A bucket ID that new blob should belong to
+      # - blob_name -> A name for new blob
+      # - blob_data -> Data stored in this blob
+      # - create_opts
+      #   - :user_metadata -> A Ruby +Hash+ with key => value metadata
+      #
+      def create_blob(bucket_id, blob_name, blob_data, create_opts={})
+        must_support! :buckets
+        create_opts.merge!(convert_meta_params(create_opts.delete(:user_metadata)))
+        response = connection.post(api_uri("buckets/#{bucket_id}")) do |request|
+          request.params = create_opts.merge(
+            :blob_id => blob_name,
+            :blob_data => blob_data
+        )
+        end
+        model(:blob).convert(self, response.body)
+      end
+
+      # Destroy given bucket blob
+      #
+      def destroy_blob(bucket_id, blob_id)
+        must_support! :buckets
+        r = connection.delete(api_uri("buckets/#{bucket_id}/#{blob_id}"))
+        r.status == 204
+      end
+
+      private
+
+      # Convert the user_metadata into POST params compatible with
+      # blob creation
+      #
+      # - params -> Simple Ruby +Hash+
+      #
+      # @return { :meta_params => COUNTER, :meta_name1 => '', :meta_value1 => ''}
+      #
+      def convert_meta_params(params)
+        meta_params = {}
+        counter = 0
+        (params || {}).each do |key, value|
+          counter += 1
+          meta_params["meta_name#{counter}"] = key
+          meta_params["meta_value#{counter}"] = value
+        end
+        if counter >= 1
+          meta_params.merge!(:meta_params => counter.to_s)
+        end
+        meta_params
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/bucket.rb b/client/lib/deltacloud/client/methods/bucket.rb
new file mode 100644
index 0000000..b68cb05
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/bucket.rb
@@ -0,0 +1,56 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module Bucket
+
+      # Retrieve list of all bucket entities
+      #
+      # Filter options:
+      #
+      # - :id -> Filter entities using 'id' attribute
+      #
+      def buckets(filter_opts={})
+        from_collection :buckets,
+          connection.get(api_uri('buckets'), filter_opts)
+      end
+
+      # Retrieve the single bucket entity
+      #
+      # - bucket_id -> Bucket entity to retrieve
+      #
+      def bucket(bucket_id)
+        from_resource :bucket,
+          connection.get(api_uri("buckets/#{bucket_id}"))
+      end
+
+      # Create a new bucket
+      #
+      # - create_opts
+      #
+      def create_bucket(name)
+        create_resource :bucket, :name => name
+      end
+
+      # Destroy given bucket
+      #
+      def destroy_bucket(bucket_id)
+        destroy_resource :bucket, bucket_id
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/common.rb b/client/lib/deltacloud/client/methods/common.rb
new file mode 100644
index 0000000..250e3a4
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/common.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.
+
+module Deltacloud::Client
+  module Methods
+    module Common
+
+      # A generic method for creating a new resources
+      #
+      # - resource_name -> A resource name to create (eg. :image)
+      # - create_opts -> HTTP options to pass into the create operation
+      #
+      def create_resource(resource_name, create_opts={})
+        no_convert_model = create_opts.delete(:no_convert_model)
+        must_support! resource_name.to_s.pluralize
+        response = connection.post(api_uri(resource_name.to_s.pluralize)) do |request|
+          request.params = create_opts
+        end
+        no_convert_model ? response : model(resource_name).convert(self, response.body)
+      end
+
+      # A generic method for destroying resources
+      #
+      def destroy_resource(resource_name, resource_id)
+        must_support! resource_name.to_s.pluralize
+        result = connection.delete(
+          api_uri([resource_name.to_s.pluralize, resource_id].join('/'))
+        )
+        result.status.is_no_content?
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/driver.rb b/client/lib/deltacloud/client/methods/driver.rb
new file mode 100644
index 0000000..107bcc3
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/driver.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::Client
+  module Methods
+    module Driver
+
+      # Retrieve list of all drivers
+      #
+      # Filter options:
+      #
+      # - :id -> Filter drivers using their 'id'
+      # - :state -> Filter drivers  by their 'state'
+      #
+      def drivers(filter_opts={})
+        from_collection(
+          :drivers,
+          connection.get(api_uri('drivers'), filter_opts)
+        )
+      end
+
+      # Retrieve the given driver
+      #
+      # - driver_id -> Driver to retrieve
+      #
+      def driver(driver_id)
+        from_resource(
+          :driver,
+          connection.get(api_uri("drivers/#{driver_id}"))
+        )
+      end
+
+      # List of the current driver providers
+      #
+      def providers
+        driver(current_driver).providers
+      end
+
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/firewall.rb b/client/lib/deltacloud/client/methods/firewall.rb
new file mode 100644
index 0000000..547dfc5
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/firewall.rb
@@ -0,0 +1,66 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module Firewall
+
+      # Retrieve list of all firewall entities
+      #
+      # Filter options:
+      #
+      # - :id -> Filter entities using 'id' attribute
+      #
+      def firewalls(filter_opts={})
+        from_collection :firewalls,
+        connection.get(api_uri('firewalls'), filter_opts)
+      end
+
+      # Retrieve the single firewall entity
+      #
+      # - firewall_id -> Firewall entity to retrieve
+      #
+      def firewall(firewall_id)
+        from_resource :firewall,
+          connection.get(api_uri("firewalls/#{firewall_id}"))
+      end
+
+      # Create a new firewall
+      #
+      # - create_opts
+      #
+      def create_firewall(name, create_opts={})
+        create_resource :firewall, { :name => name }.merge(create_opts)
+      end
+
+      def destroy_firewall(firewall_id)
+        destroy_resource :firewall, firewall_id
+      end
+
+      def add_firewall_rule(firewall_id, protocol, port_from, port_to, opts={})
+        r = connection.post(api_uri("firewalls/#{firewall_id}/rules")) do |request|
+          request.params = {
+            :protocol => protocol,
+            :port_from => port_from,
+            :port_to => port_to
+          }
+          # TODO: Add support for sources
+        end
+        model(:firewall).convert(self, r.body)
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/hardware_profile.rb b/client/lib/deltacloud/client/methods/hardware_profile.rb
new file mode 100644
index 0000000..0cf744c
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/hardware_profile.rb
@@ -0,0 +1,42 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module HardwareProfile
+
+      # Retrieve list of all hardware_profiles
+      #
+      # Filter options:
+      #
+      # - :id -> Filter hardware_profiles using their 'id'
+      #
+      def hardware_profiles(filter_opts={})
+        from_collection :hardware_profiles,
+          connection.get(api_uri('hardware_profiles'), filter_opts)
+      end
+
+      # Retrieve the given hardware_profile
+      #
+      # - hardware_profile_id -> hardware_profile to retrieve
+      #
+      def hardware_profile(hwp_id)
+        from_resource :hardware_profile,
+          connection.get(api_uri("hardware_profiles/#{hwp_id}"))
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/image.rb b/client/lib/deltacloud/client/methods/image.rb
new file mode 100644
index 0000000..8e3765b
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/image.rb
@@ -0,0 +1,62 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module Image
+
+      # Retrieve list of all images
+      #
+      # Filter options:
+      #
+      # - :id -> Filter images using their 'id'
+      # - :state -> Filter images  by their 'state'
+      # - :architecture -> Filter images  by their 'architecture'
+      #
+      def images(filter_opts={})
+        from_collection :images,
+          connection.get(api_uri('images'), filter_opts)
+      end
+
+      # Retrieve the given image
+      #
+      # - image_id -> Image to retrieve
+      #
+      def image(image_id)
+        from_resource :image,
+          connection.get(api_uri("images/#{image_id}"))
+      end
+
+      # Create a new image from instance
+      #
+      # - instance_id -> The stopped instance used for creation
+      # - create_opts
+      #   - :name     -> Name of the new image
+      #   - :description -> Description of the new image
+      #
+      def create_image(instance_id, create_opts={})
+        create_resource :image, { :instance_id => instance_id }.merge(create_opts)
+      end
+
+      # Destroy given image
+      # NOTE: This operation might not be supported for all drivers.
+      #
+      def destroy_image(image_id)
+        destroy_resource :image, image_id
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/instance.rb b/client/lib/deltacloud/client/methods/instance.rb
new file mode 100644
index 0000000..4749d82
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/instance.rb
@@ -0,0 +1,140 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module Instance
+
+      # Retrieve list of all instances
+      #
+      # Filter options:
+      #
+      # - :id -> Filter instances using their 'id'
+      # - :state -> Filter instances by their 'state'
+      # - :realm_id -> Filter instances based on their 'realm_id'
+      #
+      def instances(filter_opts={})
+        from_collection(
+          :instances,
+          connection.get(api_uri('/instances'), filter_opts)
+        )
+      end
+
+      # Retrieve the given instance
+      #
+      # - instance_id -> Instance to retrieve
+      #
+      def instance(instance_id)
+        from_resource(
+          :instance,
+          connection.get(api_uri("instances/#{instance_id}"))
+        )
+      end
+
+      # Create a new instance
+      #
+      # - image_id ->    Image to use for instance creation (img1, ami-12345, etc...)
+      # - create_opts -> Various options that DC support for the current
+      #                  provider.
+      #
+      # Returns created instance, or list of created instances or all instances.
+      #
+      def create_instance(image_id, create_opts={})
+        r = create_resource :instance, create_opts.merge(
+          :image_id => image_id,
+          :no_convert_model => true
+        )
+        parse_create_instance(r)
+      end
+
+      # Destroy the current +Instance+
+      # Returns 'true' if the response was 204 No Content
+      #
+      # - instance_id -> The 'id' of the Instance to destroy
+      #
+      def destroy_instance(instance_id)
+        destroy_resource :instance, instance_id
+      end
+
+      # Attempt to change the +Instance+ state to STOPPED
+      #
+      # - instance_id -> The 'id' of the Instance to stop
+      #
+      def stop_instance(instance_id)
+        instance_action :stop, instance_id
+      end
+
+      # Attempt to change the +Instance+ state to STARTED
+      #
+      # - instance_id -> The 'id' of the Instance to start
+      #
+      def start_instance(instance_id)
+        instance_action :start, instance_id
+      end
+
+      # Attempt to reboot the +Instance+
+      #
+      # - instance_id -> The 'id' of the Instance to reboot
+      #
+      def reboot_instance(instance_id)
+        instance_action :reboot, instance_id
+      end
+
+      private
+
+      # Avoid codu duplication ;-)
+      #
+      def instance_action(action, instance_id)
+        result = connection.post(
+          api_uri("/instances/#{instance_id}/#{action}")
+        )
+        if result.status.is_ok?
+          from_resource(:instance, result)
+        else
+          instance(instance_id)
+        end
+      end
+
+      # Handles parsing of +create_instance+ method
+      #
+      # - response -> +create_instance+ HTTP response body
+      #
+      def parse_create_instance(response)
+        # If Deltacloud API return only Location (30x), follow it and
+        # retrieve created instance from there.
+        #
+        if response.status.is_redirect?
+          # If Deltacloud API redirect to list of instances
+          # then return list of **all** instances, otherwise
+          # grab the instance_id from Location header
+          #
+          redirect_instance = response.headers['Location'].split('/').last
+          if redirect_instance == 'instances'
+            instances
+          else
+            instance(redirect_instance)
+          end
+        elsif response.body.to_xml.root.name == 'instances'
+          # If more than 1 instance was created, return list
+          #
+          from_collection(:instances, response.body)
+        else
+          from_resource(:instance, response)
+        end
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/instance_state.rb b/client/lib/deltacloud/client/methods/instance_state.rb
new file mode 100644
index 0000000..3c853d0
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/instance_state.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.
+
+module Deltacloud::Client
+  module Methods
+    module InstanceState
+
+      # Representation of the current driver state machine
+      #
+      def instance_states
+        r = connection.get(api_uri("instance_states"))
+        r.body.to_xml.root.xpath('state').map do |se|
+          state = model(:instance_state).new_state(se['name'])
+          se.xpath('transition').each do |te|
+            state.transitions << model(:instance_state).new_transition(
+              te['to'], te['action']
+            )
+          end
+          state
+        end
+      end
+
+      def instance_state(name)
+        instance_states.find { |s| s.name.to_s.eql?(name.to_s) }
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/key.rb b/client/lib/deltacloud/client/methods/key.rb
new file mode 100644
index 0000000..8984f23
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/key.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.
+
+module Deltacloud::Client
+  module Methods
+    module Key
+
+      # Retrieve list of all key entities
+      #
+      # Filter options:
+      #
+      # - :id -> Filter entities using 'id' attribute
+      #
+      def keys(filter_opts={})
+        from_collection :keys,
+          connection.get(api_uri('keys'), filter_opts)
+      end
+
+      # Retrieve the single key entity
+      #
+      # - key_id -> Key entity to retrieve
+      #
+      def key(key_id)
+        from_resource :key,
+          connection.get(api_uri("keys/#{key_id}"))
+      end
+
+      # Create a new credentials to use with authentication
+      # to an +Instance+
+      #
+      # - key_name -> The name of the key
+      # - create_opts
+      #   : public_key -> Your SSH public key (eg. ~/.ssh/id_rsa.pub)
+      #
+      def create_key(key_name, create_opts={})
+        create_resource :key, create_opts.merge(:name => key_name)
+      end
+
+      # Destroy the SSH key
+      #
+      def destroy_key(key_id)
+        destroy_resource :key, key_id
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/realm.rb b/client/lib/deltacloud/client/methods/realm.rb
new file mode 100644
index 0000000..41807f0
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/realm.rb
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module Realm
+
+      # Retrieve list of all realms
+      #
+      # Filter options:
+      #
+      # - :id -> Filter realms using their 'id'
+      # - :state -> Filter realms  by their 'state'
+      #
+      def realms(filter_opts={})
+        from_collection :realms,
+          connection.get(api_uri("realms"), filter_opts)
+      end
+
+      # Retrieve the given realm
+      #
+      # - realm_id -> Instance to retrieve
+      #
+      def realm(realm_id)
+        from_resource :realm,
+          connection.get(api_uri("realms/#{realm_id}"))
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/storage_snapshot.rb b/client/lib/deltacloud/client/methods/storage_snapshot.rb
new file mode 100644
index 0000000..33c1696
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/storage_snapshot.rb
@@ -0,0 +1,62 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module StorageSnapshot
+
+      # Retrieve list of all storage_snapshot entities
+      #
+      # Filter options:
+      #
+      # - :id -> Filter entities using 'id' attribute
+      #
+      def storage_snapshots(filter_opts={})
+        from_collection :storage_snapshots,
+          connection.get(api_uri('storage_snapshots'), filter_opts)
+      end
+
+      # Retrieve the single storage_snapshot entity
+      #
+      # - storage_snapshot_id -> StorageSnapshot entity to retrieve
+      #
+      def storage_snapshot(storage_snapshot_id)
+        from_resource :storage_snapshot,
+          connection.get(api_uri("storage_snapshots/#{storage_snapshot_id}"))
+      end
+
+      # Create a new StorageSnapshot based on +volume_id+
+      #
+      # - volume_id -> ID of the +StorageVolume+ to create snapshot from
+      # - create_opts ->
+      #   :name -> Name of the StorageSnapshot
+      #   :description -> Description of the StorageSnapshot
+      #
+      def create_storage_snapshot(volume_id, create_opts={})
+        create_resource :storage_snapshot, create_opts.merge(:volume_id => volume_id)
+      end
+
+      # Destroy the current +StorageSnapshot+
+      # Returns 'true' if the response was 204 No Content
+      #
+      # - snapshot_id -> The 'id' of the snapshot to destroy
+      #
+      def destroy_storage_snapshot(snapshot_id)
+        destroy_resource :storage_snapshot, snapshot_id
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/methods/storage_volume.rb b/client/lib/deltacloud/client/methods/storage_volume.rb
new file mode 100644
index 0000000..be6c4ca
--- /dev/null
+++ b/client/lib/deltacloud/client/methods/storage_volume.rb
@@ -0,0 +1,95 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  module Methods
+    module StorageVolume
+
+      # Retrieve list of all storage_volumes
+      #
+      # Filter options:
+      #
+      # - :id -> Filter storage_volumes using their 'id'
+      # - :state -> Filter storage_volumes  by their 'state'
+      #
+      def storage_volumes(filter_opts={})
+        from_collection :storage_volumes,
+          connection.get(api_uri("storage_volumes"), filter_opts)
+      end
+
+      # Retrieve the given storage_volume
+      #
+      # - storage_volume_id -> Instance to retrieve
+      #
+      def storage_volume(storage_volume_id)
+        from_resource :storage_volume,
+          connection.get(api_uri("storage_volumes/#{storage_volume_id}"))
+      end
+
+      # Create new storage volume
+      #
+      # - :snapshot_id -> Snapshot to use for creating a new volume
+      # - :capacity    -> Initial Volume capacity
+      # - :realm_id    -> Create volume in this realm
+      # - :name        -> Volume name
+      # - :description -> Volume description
+      #
+      # NOTE: Some create options might not be supported by backend cloud
+      #
+      def create_storage_volume(create_opts={})
+        create_resource :storage_volume, create_opts
+      end
+
+      # Destroy the current +StorageVolume+
+      # Returns 'true' if the response was 204 No Content
+      #
+      # - volume_id -> The 'id' of the volume to destroy
+      #
+      def destroy_storage_volume(volume_id)
+        destroy_resource :storage_volume, volume_id
+      end
+
+      # Attach the Storage Volume to the Instance
+      # The +device+ parameter could be used if supported.
+      #
+      # - volume_id -> Volume ID (eg. 'vol1')
+      # - instance_id -> Target Instance ID (eg. 'inst1')
+      # - device -> Target device in Instance (eg. '/dev/sda2')
+      #
+      def attach_storage_volume(volume_id, instance_id, device=nil)
+        must_support! :storage_volumes
+        result = connection.post(api_uri("/storage_volumes/#{volume_id}/attach")) do |r|
+          r.params = { :instance_id => instance_id, :device => device }
+        end
+        if result.status.is_ok?
+          from_resource(:storage_volume, result)
+        end
+      end
+
+      # Detach the Storage Volume from the Instance
+      #
+      # -volume_id -> Volume to detach
+      #
+      def detach_storage_volume(volume_id)
+        must_support! :storage_volumes
+        result = connection.post(api_uri("/storage_volumes/#{volume_id}/detach"))
+        if result.status.is_ok?
+          from_resource(:storage_volume, result)
+        end
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models.rb b/client/lib/deltacloud/client/models.rb
new file mode 100644
index 0000000..63b5a24
--- /dev/null
+++ b/client/lib/deltacloud/client/models.rb
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 './models/base'
+require_relative './models/driver'
+require_relative './models/realm'
+require_relative './models/hardware_profile'
+require_relative './models/image'
+require_relative './models/instance_address'
+require_relative './models/instance'
+require_relative './models/instance_state'
+require_relative './models/storage_volume'
+require_relative './models/storage_snapshot'
+require_relative './models/key'
+require_relative './models/address'
+require_relative './models/bucket'
+require_relative './models/blob'
+require_relative './models/firewall'
diff --git a/client/lib/deltacloud/client/models/address.rb b/client/lib/deltacloud/client/models/address.rb
new file mode 100644
index 0000000..d39d80b
--- /dev/null
+++ b/client/lib/deltacloud/client/models/address.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::Client
+  class Address < Base
+    include Deltacloud::Client::Methods::Address
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    attr_reader :ip
+    attr_reader :instance_id
+
+    # Address model methods
+    #
+
+    # Associate the IP address to the +Instance+
+    #
+    def associate(instance_id)
+      associate_address(_id, instance_id)
+    end
+
+    # Disassociate the IP address from +Instance+
+    #
+    def disassociate
+      disassociate_address(_id)
+    end
+
+    def destroy!
+      destroy_address(_id)
+    end
+
+    # Parse the Address entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the address
+    #
+    def self.parse(xml_body)
+      {
+        :ip => xml_body.text_at(:ip),
+        :instance_id => xml_body.attr_at('instance', :id)
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/base.rb b/client/lib/deltacloud/client/models/base.rb
new file mode 100644
index 0000000..9f51fb0
--- /dev/null
+++ b/client/lib/deltacloud/client/models/base.rb
@@ -0,0 +1,151 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+
+  class Base
+
+    extend Helpers::XmlHelper
+
+    include Deltacloud::Client::Helpers::Model
+    include Deltacloud::Client::Methods::Api
+
+    # These attributes are common for all models
+    #
+    # - obj_id -> The :id of Deltacloud API model (eg. instance ID)
+    #
+    attr_reader :obj_id
+    attr_reader :name
+    attr_reader :description
+
+    # The Base class that other models should inherit from
+    # To initialize, you need to suply these mandatory params:
+    #
+    # - :_client -> Reference to Client instance
+    # - :_id     -> The 'id' of resource. The '_' is there to avoid conflicts
+    #
+    def initialize(opts={})
+      @options = opts
+      @obj_id = @options.delete(:_id)
+      # Do not allow to modify the object#base_id
+      @obj_id.freeze
+      @client = @options.delete(:_client)
+      @original_body = @options.delete(:original_body)
+      update_instance_variables!(@options)
+    end
+
+    alias_method :_id, :obj_id
+
+    # Populate instance variables in model
+    # This method could be also used to update the variables for already
+    # initialized models. Look at +Instance#reload!+ method.
+    #
+    def update_instance_variables!(opts={})
+      @options.merge!(opts)
+      @options.each { |key, val| self.instance_variable_set("@#{key}", val) unless val.nil? }
+      self
+    end
+
+    # Eye-candy representation of model, without ugly @client representation
+    #
+    def to_s
+      "#<#{self.class.name}> #{@options.merge(:_id => @obj_id).inspect}"
+    end
+
+    # An internal reference to the current Deltacloud::Client::Connection
+    # instance. Used for implementing the model methods
+    #
+    def client
+      @client
+    end
+
+    # Shorthand for +client+.connection
+    #
+    # Return Faraday connection object.
+    #
+    def connection
+      client.connection
+    end
+
+    # Return the cached version of Deltacloud API entrypoint
+    #
+    def entrypoint
+      client.entrypoint
+    end
+
+    # Return the original XML body model was constructed from
+    # This might help debugging broken XML
+    #
+    def original_body
+      @original_body
+    end
+
+    # The model#id is the old way how to get the Deltacloud API resource
+    # 'id'. However this collide with the Ruby Object#id.
+    #
+    def id
+      warn '[DEPRECATION] `id` is deprecated because of possible conflict with Object#id. Use `_id` instead.'
+      _id
+    end
+
+    class << self
+
+      # Parse the XML response body from Deltacloud API
+      # to +Hash+. Result is then used to create an instance of Deltacloud model
+      #
+      # NOTE: Children classes **must** implement this class method
+      #
+      def parse(client_ref, inst)
+        warn "The self#parse method **must** be defined in #{self.class.name}"
+        {}
+      end
+
+      # Convert the parsed +Hash+ from +parse+ method to instance of Deltacloud model
+      #
+      # - client_ref -> Reference to the Client instance
+      # - obj -> Might be a Nokogiri::Element or Response
+      #
+      def convert(client_ref, obj)
+        body = extract_xml_body(obj).to_xml.root
+        attrs = parse(body)
+        attrs.merge!({
+          :_id => body['id'],
+          :_client => client_ref,
+          :name => body.text_at(:name),
+          :description => body.text_at(:description)
+        })
+        validate_attrs!(attrs)
+        new(attrs.merge(:original_body => obj))
+      end
+
+      # Convert response for the collection responses.
+      #
+      def from_collection(client_ref, response)
+        response.body.to_xml.xpath('/*/*').map do |entity|
+          convert(client_ref, entity)
+        end
+      end
+
+      # The :_id and :_client attributes are mandotory
+      # to construct a Base model object.
+      #
+      def validate_attrs!(attrs)
+        raise error.new('The :_id must not be nil.') if attrs[:_id].nil?
+        raise error.new('The :_client reference is missing.') if attrs[:_client].nil?
+      end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/blob.rb b/client/lib/deltacloud/client/models/blob.rb
new file mode 100644
index 0000000..569c187
--- /dev/null
+++ b/client/lib/deltacloud/client/models/blob.rb
@@ -0,0 +1,56 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class Blob < Base
+
+    include Deltacloud::Client::Methods::Blob
+    include Deltacloud::Client::Methods::Bucket
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    attr_reader :bucket_id
+    attr_reader :content_length
+    attr_reader :content_type
+    attr_reader :last_modified
+    attr_reader :user_metadata
+
+    # Blob model methods
+    #
+
+    def bucket
+      super(bucket_id)
+    end
+
+    # Parse the Blob entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the blob
+    #
+    def self.parse(xml_body)
+      {
+        :bucket_id => xml_body.text_at(:bucket_id) || xml_body.text_at(:bucket), # FIXME: DC bug
+        :content_length => xml_body.text_at(:content_length),
+        :content_type => xml_body.text_at(:content_type),
+        :last_modified => xml_body.text_at(:last_modified),
+        :user_metadata => xml_body.xpath('user_metadata/entry').inject({}) { |r,e|
+          r[e['key']] = e.text.strip
+          r
+        }
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/bucket.rb b/client/lib/deltacloud/client/models/bucket.rb
new file mode 100644
index 0000000..9a8a856
--- /dev/null
+++ b/client/lib/deltacloud/client/models/bucket.rb
@@ -0,0 +1,65 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class Bucket < Base
+
+    include Deltacloud::Client::Methods::Bucket
+    include Deltacloud::Client::Methods::Blob
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    attr_reader :size
+    attr_reader :blob_ids
+
+    # Bucket model methods
+    #
+    #
+
+    # All blobs associated with the current bucket
+    # The 'bucket_id' should not be set in this case.
+    #
+    def blobs(bucket_id=nil)
+      super(_id)
+    end
+
+    # Add a new blob to the bucket.
+    # See: +create_blob+
+    #
+    def add_blob(blob_name, blob_data, blob_create_opts={})
+      create_blob(_id, blob_name, blob_data, create_opts)
+    end
+
+    # Remove a blob from the bucket
+    # See: +destroy_blob+
+    #
+    def remove_blob(blob_id)
+      destroy_blob(_id, blob_id)
+    end
+
+    # Parse the Bucket entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the bucket
+    #
+    def self.parse(xml_body)
+      {
+        :size => xml_body.text_at(:size),
+        :blob_ids => xml_body.xpath('blob').map { |b| b['id'] }
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/driver.rb b/client/lib/deltacloud/client/models/driver.rb
new file mode 100644
index 0000000..538d463
--- /dev/null
+++ b/client/lib/deltacloud/client/models/driver.rb
@@ -0,0 +1,87 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+
+  class Driver < Base
+
+    attr_reader :providers
+
+    # Syntax sugar for returning provider from Driver
+    # instance:
+    #
+    # client.driver(:ec2)['us-west-1'] # => List of endpoints
+    #
+    # - provider_id -> Provider ID, like 'us-west-1'
+    #
+    def [](provider_id)
+      @providers ||= []
+      prov = @providers.find { |p| p.name == provider_id }
+      prov.instance_variable_set('@client', @client)
+      prov
+    end
+
+    def self.parse(xml_body)
+      {
+        :providers => xml_body.xpath('provider').map { |p| Provider.parse(p) }
+      }
+    end
+
+    class Provider
+
+      attr_reader :name
+      attr_reader :entrypoints
+
+      def initialize(name, entrypoints=[])
+        @name = name
+        @entrypoints = entrypoints
+      end
+
+      # Syntax sugar for retrieving list of endpoints available for the
+      # provider
+      #
+      # - entrypoint_id -> Entrypoint ID, like 's3'
+      #
+      def [](entrypoint_id)
+        @entrypoints ||= []
+        ent_point = @entrypoints.find { |name, _| name == entrypoint_id }
+        ent_point ? ent_point.last : nil
+      end
+
+      # Method to check if given credentials can be used to authorize
+      # connection to current provider:
+      #
+      # client.driver(:ec2)['us-west-1'].valid_credentials? 'user', 'password'
+      #
+      # - api_user -> API key
+      # - api_password -> API secret
+      #
+      def valid_credentials?(api_user, api_password)
+        unless @client
+          raise error.new('Please use driver("ec2")[API_PROVIDER].valid_credentials?')
+        end
+        @client.use(@client.current_driver, api_user, api_password, @name).valid_credentials?
+      end
+
+      def self.parse(p)
+        new(
+          p['id'],
+          p.xpath('entrypoint').inject({}) { |r, e| r[e['kind']] = e.text.strip; r }
+        )
+      end
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/client/models/firewall.rb b/client/lib/deltacloud/client/models/firewall.rb
new file mode 100644
index 0000000..9bbe0f2
--- /dev/null
+++ b/client/lib/deltacloud/client/models/firewall.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::Client
+  class Firewall < Base
+
+    include Deltacloud::Client::Methods::Common
+    include Deltacloud::Client::Methods::Firewall
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    attr_reader :owner_id
+    attr_reader :rules
+
+    # Firewall model methods
+    #
+    # def reboot!
+    #   firewall_reboot(_id)
+    # end
+
+    # Parse the Firewall entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the firewall
+    #
+    def self.parse(xml_body)
+      {
+        :owner_id => xml_body.text_at(:owner_id),
+        :rules => xml_body.xpath('rules/rule').map { |rule|
+          Rule.convert(self, rule)
+        }
+      }
+    end
+
+    class Rule < Deltacloud::Client::Base
+
+      attr_reader :allow_protocol
+      attr_reader :port_from
+      attr_reader :port_to
+      attr_reader :direction
+      attr_reader :sources
+
+     def self.parse(xml_body)
+       {
+        :allow_protocol => xml_body.text_at(:allow_protocol),
+        :port_from => xml_body.text_at(:port_from),
+        :port_to => xml_body.text_at(:port_to),
+        :direction => xml_body.text_at(:direction),
+        :sources => xml_body.xpath('sources/source').map { |s|
+          { :name => s['name'], :owner => s['owner'], :type => s['type'] }
+        }
+       }
+     end
+
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/hardware_profile.rb b/client/lib/deltacloud/client/models/hardware_profile.rb
new file mode 100644
index 0000000..83432b8
--- /dev/null
+++ b/client/lib/deltacloud/client/models/hardware_profile.rb
@@ -0,0 +1,68 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud::Client
+  class HardwareProfile < Base
+
+    include Deltacloud::Client::Helpers
+
+    attr_reader :properties
+
+    def self.parse(hwp)
+      {
+        :properties => hwp.xpath('property').map { |p|
+          property_klass(p['kind']).parse(p)
+        }
+      }
+    end
+
+    def cpu
+      property :cpu
+    end
+
+    def memory
+      property :memory
+    end
+
+    def architecture
+      property :architecture
+    end
+
+    def storage
+      property :storage
+    end
+
+    def opaque?
+      @properties.empty? && @name == 'opaque'
+    end
+
+    private
+
+    def property(name)
+      @properties.find { |p| p.name == name.to_s }
+    end
+
+    def self.property_klass(kind)
+      case kind
+        when 'enum'   then Property::Enum
+        when 'range'  then Property::Range
+        when 'fixed'  then Property::Fixed
+        when 'opaque' then Property::Property
+        else raise error.new("Unknown HWP property: #{kind}")
+      end
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/client/models/image.rb b/client/lib/deltacloud/client/models/image.rb
new file mode 100644
index 0000000..8599f41
--- /dev/null
+++ b/client/lib/deltacloud/client/models/image.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.
+
+module Deltacloud::Client
+  class Image < Base
+
+    attr_reader :owner_id, :architecture, :state
+    attr_reader :creation_time, :root_type, :hardware_profile_ids
+
+    def hardware_profiles
+      @client.hardware_profiles.select { |hwp| @hardware_profile_ids.include?(hwp._id) }
+    end
+
+    def is_compatible?(hardware_profile_id)
+      hardware_profile_ids.include? hardware_profile_id
+    end
+
+    # Launch the image using +Instance+#+create_instance+ method.
+    # This method is more strict in checking +HardwareProfile+
+    # and in case you use incompatible HWP it raise an error.
+    #
+    # - create_instance_opts -> +create_instance+ options
+    #
+    def launch(create_instance_opts={})
+
+      if hwp_id = create_instance_opts[:hwp_id]
+        raise error(:incompatible_hardware_profile).new(
+          "Profile '#{hwp_id}' is not compatible with this image."
+        ) unless is_compatible?(hwp_id)
+      end
+
+      @client.create_instance(self._id, create_instance_opts)
+    end
+
+    def self.parse(xml_body)
+      {
+        :owner_id =>        xml_body.text_at(:owner_id),
+        :architecture =>    xml_body.text_at(:architecture),
+        :state =>           xml_body.text_at(:state),
+        :creation_time =>   xml_body.text_at('creation_time'),
+        :root_type =>       xml_body.text_at('root_type'),
+        :hardware_profile_ids => xml_body.xpath('hardware_profiles/hardware_profile').map { |h|
+          h['id']
+        }
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/instance.rb b/client/lib/deltacloud/client/models/instance.rb
new file mode 100644
index 0000000..01e1882
--- /dev/null
+++ b/client/lib/deltacloud/client/models/instance.rb
@@ -0,0 +1,122 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class Instance < Base
+
+    include Deltacloud::Client::Methods::Common
+    include Deltacloud::Client::Methods::Instance
+    include Deltacloud::Client::Methods::Realm
+    include Deltacloud::Client::Methods::HardwareProfile
+    include Deltacloud::Client::Methods::Image
+
+    attr_reader :realm_id
+    attr_reader :owner_id
+    attr_reader :image_id
+    attr_reader :hardware_profile_id
+
+    attr_accessor :state
+    attr_accessor :public_addresses
+    attr_accessor :private_addresses
+
+    # Destroy the current Instance
+    #
+    def destroy!
+      destroy_instance(_id)
+    end
+
+    # Execute +stop_instance+ method on current Instance
+    #
+    def stop!
+      stop_instance(_id) && reload!
+    end
+
+    # Execute +start_instance+ method on current Instance
+    #
+    def start!
+      start_instance(_id) && reload!
+    end
+
+    # Execute +reboot_instance+ method on current Instance
+    #
+    def reboot!
+      reboot_instance(_id) && reload!
+    end
+
+    # Retrieve the +Realm+ associated with Instance
+    #
+    def realm
+      super(realm_id)
+    end
+
+    def hardware_profile
+      super(hardware_profile_id)
+    end
+
+    def image
+      super(image_id)
+    end
+
+    def method_missing(name, *args)
+      return self.state.downcase == $1 if name.to_s =~ /^is_(\w+)\?$/
+      super
+    end
+
+    # Helper for is_STATE?
+    #
+    # is_running?
+    # is_stopped?
+    #
+    def method_missing(name, *args)
+      if name =~ /^is_(\w+)\?$/
+        return state == $1.upcase
+      end
+      super
+    end
+
+    class << self
+
+      def parse(xml_body)
+        {
+          :state =>               xml_body.text_at('state'),
+          :owner_id =>            xml_body.text_at('owner_id'),
+          :realm_id =>            xml_body.attr_at('realm', :id),
+          :image_id =>            xml_body.attr_at('image', :id),
+          :hardware_profile_id => xml_body.attr_at('hardware_profile', :id),
+          :public_addresses => InstanceAddress.convert(
+            xml_body.xpath('public_addresses/address')
+          ),
+          :private_addresses => InstanceAddress.convert(
+            xml_body.xpath('private_addresses/address')
+          )
+        }
+      end
+
+    end
+
+    # Attempt to reload :public_addresses, :private_addresses and :state
+    # of the instance, after the instance is modified by calling method
+    #
+    def reload!
+      new_instance = instance(_id)
+      update_instance_variables!(
+        :public_addresses => new_instance.public_addresses,
+        :private_addresses => new_instance.private_addresses,
+        :state => new_instance.state
+      )
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/client/models/instance_address.rb b/client/lib/deltacloud/client/models/instance_address.rb
new file mode 100644
index 0000000..f40c264
--- /dev/null
+++ b/client/lib/deltacloud/client/models/instance_address.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.
+
+module Deltacloud::Client
+  class InstanceAddress < OpenStruct
+
+    attr_reader :type
+    attr_reader :value
+
+    def to_s
+      @value
+    end
+
+    def self.convert(address_xml_block)
+      address_xml_block.map do |addr|
+        new(
+          :type => addr['type'],
+          :value => addr.text
+        )
+      end
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/instance_state.rb b/client/lib/deltacloud/client/models/instance_state.rb
new file mode 100644
index 0000000..79dddad
--- /dev/null
+++ b/client/lib/deltacloud/client/models/instance_state.rb
@@ -0,0 +1,52 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+
+  class InstanceState
+
+    def self.new_state(name)
+      State.new(name)
+    end
+
+    def self.new_transition(to, action)
+      Transition.new(to, action)
+    end
+
+    class State
+      attr_reader :name
+      attr_reader :transitions
+
+      def initialize(name)
+        @name, @transitions = name, []
+      end
+    end
+
+    class Transition
+      attr_reader :to
+      attr_reader :action
+
+      def initialize(to, action)
+        @to = to
+        @action = action
+      end
+
+      def auto?
+        @action.nil?
+      end
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/client/models/key.rb b/client/lib/deltacloud/client/models/key.rb
new file mode 100644
index 0000000..da38ee5
--- /dev/null
+++ b/client/lib/deltacloud/client/models/key.rb
@@ -0,0 +1,52 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class Key < Base
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    attr_reader :state
+    attr_reader :username
+    attr_reader :password
+    attr_reader :public_key
+    attr_reader :fingerprint
+
+    # Key model methods
+    def pem
+      @public_key
+    end
+
+    def destroy!
+      destroy_key(_id)
+    end
+
+    # Parse the Key entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the key
+    #
+    def self.parse(xml_body)
+      {
+        :state => xml_body.text_at(:state),
+        :username => xml_body.text_at(:username),
+        :password => xml_body.text_at(:password),
+        :fingerprint => xml_body.text_at(:fingerprint),
+        :public_key => xml_body.text_at(:pem)
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/realm.rb b/client/lib/deltacloud/client/models/realm.rb
new file mode 100644
index 0000000..d01739c
--- /dev/null
+++ b/client/lib/deltacloud/client/models/realm.rb
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class Realm < Base
+
+    attr_reader :limit
+    attr_reader :state
+
+    def self.parse(xml_body)
+      {
+        :state => xml_body.text_at('state'),
+        :limit => xml_body.text_at('limit')
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/storage_snapshot.rb b/client/lib/deltacloud/client/models/storage_snapshot.rb
new file mode 100644
index 0000000..f844e9f
--- /dev/null
+++ b/client/lib/deltacloud/client/models/storage_snapshot.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::Client
+  class StorageSnapshot < Base
+
+    include Deltacloud::Client::Methods::StorageSnapshot
+    include Deltacloud::Client::Methods::StorageVolume
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    attr_reader :created
+    attr_reader :storage_volume_id
+
+    # StorageSnapshot model methods
+    #
+    def storage_volume
+      super(storage_volume_id)
+    end
+
+    # Syntax sugar for destroying the current instance
+    # of StorageSnapshot
+    #
+    def destroy!
+      destroy_storage_snapshot(_id)
+    end
+
+
+    # Parse the StorageSnapshot entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the storage_snapshot
+    #
+    def self.parse(xml_body)
+      {
+        :created => xml_body.text_at(:created),
+        :storage_volume_id => xml_body.attr_at('storage_volume', :id)
+      }
+    end
+  end
+end
diff --git a/client/lib/deltacloud/client/models/storage_volume.rb b/client/lib/deltacloud/client/models/storage_volume.rb
new file mode 100644
index 0000000..26e1e80
--- /dev/null
+++ b/client/lib/deltacloud/client/models/storage_volume.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 Deltacloud::Client
+  class StorageVolume < Base
+
+    include Deltacloud::Client::Methods::Common
+    include Deltacloud::Client::Methods::Instance
+    include Deltacloud::Client::Methods::StorageVolume
+    include Deltacloud::Client::Methods::StorageSnapshot
+
+    attr_accessor :created
+    attr_accessor :state
+    attr_accessor :capacity
+    attr_accessor :capacity_unit
+    attr_accessor :device
+    attr_accessor :realm_id
+    attr_accessor :kind
+    attr_accessor :mount
+
+    # Check if the current volume is attached to an Instance
+    #
+    def attached?
+      !mount[:instance].nil?
+    end
+
+    # Attach this volume to the instance
+    #
+    def attach(instance_id, device=nil)
+      attach_storage_volume(_id, instance_id, device) && reload!
+    end
+
+    # Detach this volume from the currently attached instance
+    #
+    def detach!
+      detach_storage_volume(_id) && reload!
+    end
+
+    # Destroy the storage volume
+    #
+    def destroy!
+      destroy_storage_volume(_id)
+    end
+
+    # Syntax sugar for creating a snapshot from volume
+    # See: +create_storage_snapshot+
+    #
+    def snapshot!(snapshot_opts={})
+      snap = create_storage_snapshot(_id, snapshot_opts)
+      reload! && snap
+    end
+
+    def instance
+      super(mount[:instance])
+    end
+
+    def self.parse(xml_body)
+      {
+        :created =>             xml_body.text_at('created'),
+        :state =>               xml_body.text_at('state'),
+        :device =>              xml_body.text_at('device'),
+        :capacity =>            xml_body.text_at('capacity'),
+        :capacity_unit =>       xml_body.attr_at('capacity', :unit),
+        :state =>               xml_body.text_at('state'),
+        :realm_id =>            xml_body.attr_at('realm', :id),
+        :kind  =>               xml_body.text_at('kind'),
+        :mount  =>              {
+          :instance => xml_body.attr_at('mount/instance', :id),
+          :device => xml_body.attr_at('mount/device', :name)
+        }
+      }
+    end
+
+    private
+
+    def reload!
+      new_volume = storage_volume(_id)
+      update_instance_variables!(
+        :state => new_volume.state,
+        :mount => new_volume.mount
+      )
+    end
+  end
+end
diff --git a/client/lib/deltacloud/core_ext.rb b/client/lib/deltacloud/core_ext.rb
new file mode 100644
index 0000000..e85cdba
--- /dev/null
+++ b/client/lib/deltacloud/core_ext.rb
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 './core_ext/element'
+require_relative './core_ext/string'
+require_relative './core_ext/fixnum'
+require_relative './core_ext/string'
diff --git a/client/lib/deltacloud/core_ext/element.rb b/client/lib/deltacloud/core_ext/element.rb
new file mode 100644
index 0000000..43b3c61
--- /dev/null
+++ b/client/lib/deltacloud/core_ext/element.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 Nokogiri
+  module XML
+
+    class Element
+
+      def text_at(xpath)
+        (val = self.at(xpath)) ? val.text.strip : nil
+      end
+
+      def attr_at(xpath, attr_name)
+        (val = self.at(xpath)) ? val[attr_name.to_s.strip] : nil
+      end
+
+    end
+
+  end
+end
diff --git a/client/lib/deltacloud/core_ext/fixnum.rb b/client/lib/deltacloud/core_ext/fixnum.rb
new file mode 100644
index 0000000..5eb6e1b
--- /dev/null
+++ b/client/lib/deltacloud/core_ext/fixnum.rb
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 Fixnum
+
+  def is_redirect?
+    (self.to_s =~ /^3(\d+)$/) ? true : false
+  end
+
+  def is_ok?
+    (self.to_s =~ /^2(\d+)$/) ? true : false
+  end
+
+  def is_no_content?
+    self == 204
+  end
+
+end
diff --git a/client/lib/deltacloud/core_ext/nil.rb b/client/lib/deltacloud/core_ext/nil.rb
new file mode 100644
index 0000000..6612326
--- /dev/null
+++ b/client/lib/deltacloud/core_ext/nil.rb
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 NilClass
+
+  def to_xml
+    raise Deltacloud::Client::InvalidXMLError.new('Server returned empty body')
+  end
+
+end
diff --git a/client/lib/deltacloud/core_ext/string.rb b/client/lib/deltacloud/core_ext/string.rb
new file mode 100644
index 0000000..e02aacf
--- /dev/null
+++ b/client/lib/deltacloud/core_ext/string.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 String
+
+  # Used to automagically convert any XML in String
+  # (like HTTP response body) to Nokogiri::XML object
+  #
+  # If Nokogiri::XML fails, InvalidXMLError is returned.
+  #
+  def to_xml
+    Nokogiri::XML(self)
+  end
+
+  unless method_defined? :camelize
+    def camelize
+      split('_').map { |w| w.capitalize }.join
+    end
+  end
+
+  unless method_defined? :pluralize
+    def pluralize
+      return self + 'es' if self =~ /ess$/
+      return self[0, self.length-1] + "ies" if self =~ /ty$/
+      return self if self =~ /data$/
+      self + "s"
+    end
+  end
+
+  unless method_defined? :singularize
+    def singularize
+      return self.gsub(/ies$/, 'y') if self =~ /ies$/
+      return self.gsub(/es$/, '') if self =~ /sses$/
+      self.gsub(/s$/, '')
+    end
+  end
+end
diff --git a/client/lib/deltacloud/error_response.rb b/client/lib/deltacloud/error_response.rb
new file mode 100644
index 0000000..428b5ec
--- /dev/null
+++ b/client/lib/deltacloud/error_response.rb
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 ErrorResponse < Faraday::Response::Middleware
+
+    include Deltacloud::Client::Helpers::Model
+
+    # This method tries to parse the error XML from Deltacloud API
+    # In case there is no error returned in body, it will try to use
+    # the generic error reporting.
+    #
+    # - klass -> Deltacloud::Client::+Class+
+    # - message -> Exception message (overiden by error body message if
+    #              present)
+    # - error -> Deltacloud XML error representation
+    #
+    def client_error(name, error, message=nil)
+      args = {
+        :message => message,
+        :status => error ? error[:status] : '500'
+      }
+      # If Deltacloud API send error in response body, parse it.
+      # Otherwise, when DC API send just plain text error, use
+      # it as exception message.
+      # If DC API does not send anything back, then fallback to
+      # the 'message' attribute.
+      #
+      if error and !error[:body].empty?
+        if xml_error?(error)
+          args.merge! parse_error(error[:body].to_xml.root)
+        else
+          args[:message] = error[:body]
+        end
+      end
+      error(name).new(args)
+    end
+
+    def call(env)
+      @app.call(env).on_complete do |e|
+        case e[:status].to_s
+        when '401'
+          raise client_error(:authentication_error, e, 'Invalid :api_user or :api_password')
+        when '405'
+          raise client_error(
+            :invalid_state, e, 'Resource state does not permit this action'
+          )
+        when '404'
+          raise client_error(:not_found, e, 'Object not found')
+        when /40\d/
+          raise client_error(:client_failure, e)
+        when '500'
+          raise client_error(:server_error, e)
+        when '502'
+          raise client_error(:backend_error, e)
+        when '501'
+          raise client_error(:not_supported, e)
+        end
+      end
+    end
+
+    private
+
+    def xml_error?(error)
+      error[:body].to_xml.root && error[:body].to_xml.root.name == 'error'
+    end
+
+    # Parse the Deltacloud API error body to Hash
+    #
+    def parse_error(body)
+      args = {}
+      args[:original_error] = body.to_s
+      args[:server_backtrace] = body.text_at('backtrace')
+      args[:message] ||= body.text_at('message')
+      args[:driver] = body.attr_at('backend', 'driver')
+      args[:provider] = body.attr_at('backend', 'provider')
+      args
+    end
+  end
+end
diff --git a/client/lib/documentation.rb b/client/lib/documentation.rb
deleted file mode 100644
index 88f0861..0000000
--- a/client/lib/documentation.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.
-
-module DeltaCloud
-  class Documentation
-
-    attr_reader :api, :description, :params, :collection_operations
-    attr_reader :collection, :operation
-
-    def initialize(api, opts={})
-      @description, @api = opts[:description], api
-      @params = parse_parameters(opts[:params]) if opts[:params]
-      @collection_operations = opts[:operations] if opts[:operations]
-      @collection = opts[:collection]
-      @operation = opts[:operation]
-      self
-    end
-
-    def operations
-      @collection_operations.collect { |o| api.documentation(@collection, o) }
-    end
-
-    class OperationParameter
-      attr_reader :name
-      attr_reader :type
-      attr_reader :required
-      attr_reader :description
-
-      def initialize(data)
-        @name, @type, @required, @description = data[:name], data[:type], data[:required], data[:description]
-      end
-
-      def to_comment
-        "   # @param [#{@type}, #{@name}] #{@description}"
-      end
-
-    end
-
-    private
-
-    def parse_parameters(params)
-      params.collect { |p| OperationParameter.new(p) }
-    end
-
-  end
-
-end
diff --git a/client/lib/errors.rb b/client/lib/errors.rb
deleted file mode 100644
index d0eff44..0000000
--- a/client/lib/errors.rb
+++ /dev/null
@@ -1,140 +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 HTTPError
-
-    class ClientError < StandardError
-
-      attr_reader :params, :driver, :provider
-
-      def initialize(code, message, opts={}, backtrace=nil)
-        @params, @driver, @provider = opts[:params], opts[:driver], opts[:provider]
-        if code.to_s =~ /^5(\d{2})/
-          message += "\nParameters: #{@params.inspect}\n"
-          message += "Driver: #{@driver}@#{@provider}"
-        end
-        super("#{code}\n\n#{self.class.superclass}: #{message}\n\n")
-        # If server provided us the backtrace, then replace client backtrace
-        # with the server one.
-        set_backtrace(backtrace) unless backtrace.nil?
-      end
-    end
-
-    class ServerError < ClientError; end
-    class UknownError < ClientError; end
-
-    # For sake of consistent documentation we need to create
-    # this exceptions manually, instead of using some meta-programming.
-    # Client will really appreciate this it will try to catch some
-    # specific exception.
-
-    # Client errors (4xx)
-    class BadRequest < ClientError; end
-    class Unauthorized < ClientError; end
-    class Forbidden < ClientError; end
-    class NotFound < ClientError; end
-    class MethodNotAllowed < ClientError; end
-    class NotAcceptable < ClientError; end
-    class RequestTimeout < ClientError; end
-    class Gone < ClientError; end
-    class ExpectationFailed < ClientError; end
-    class UnsupportedMediaType < ClientError; end
-
-    # Server errors (5xx)
-    class DeltacloudError < ServerError; end
-    class ProviderError < ServerError; end
-    class ProviderTimeout < ServerError; end
-    class ServiceUnavailable < ServerError; end
-    class NotImplemented < ServerError; end
-
-    class ExceptionHandler
-
-      attr_reader :http_status_code, :message, :trace
-
-      def initialize(status_code, message=nil, opts={}, backtrace=nil, &block)
-        @http_status_code = status_code.to_i
-        @trace = backtrace
-        @message = message || client_error_messages[status_code] || 'No error message received'
-        @options = opts
-        instance_eval(&block) if block_given?
-      end
-
-      def on(code, exception_class)
-        if code == @http_status_code
-          raise exception_class.new(code, @message, @options, @trace)
-        end
-      end
-
-      private
-
-      def client_error_messages
-        {
-          400 => 'The request could not be understood by the server due to malformed syntax.',
-          401 => 'Authentication required for this request or invalid credentials provided.',
-          403 => 'Requested operation is not allowed for this resource.',
-          404 => 'Not Found',
-          405 => 'Method not allowed for this resource.',
-          406 => 'Requested media type is not supported by server.',
-          408 => 'The client did not produce a request within the time that the server was prepared to wait.',
-          410 => 'The resource is no longer available'
-        }
-      end
-
-    end
-
-    def self.parse_response_error(response)
-    
-    end
-
-    def self.client_error(code)
-      ExceptionHandler.new(code) do
-        # Client errors
-        on 400, BadRequest
-        on 401, Unauthorized
-        on 403, Forbidden
-        on 404, NotFound
-        on 405, MethodNotAllowed
-        on 406, NotAcceptable
-        on 408, RequestTimeout
-        on 410, Gone
-      end
-    end
-
-    def self.server_error(code, message, opts={}, backtrace=nil)
-      ExceptionHandler.new(code, message, opts, backtrace) do
-        # Client errors
-        on 400, BadRequest
-        on 401, Unauthorized
-        on 403, Forbidden
-        on 404, NotFound
-        on 405, MethodNotAllowed
-        on 406, NotAcceptable
-        on 408, RequestTimeout
-        on 410, Gone
-        on 415, UnsupportedMediaType
-        on 417, ExpectationFailed
-        # Server errors
-        on 500, DeltacloudError
-        on 501, NotImplemented
-        on 502, ProviderError
-        on 503, ServiceUnavailable
-        on 504, ProviderTimeout
-      end
-      raise Deltacloud::HTTPError::UnknownError.new(code, message, opts, backtrace)
-    end
-
-  end
-end
diff --git a/client/lib/hwp_properties.rb b/client/lib/hwp_properties.rb
deleted file mode 100644
index 686deaa..0000000
--- a/client/lib/hwp_properties.rb
+++ /dev/null
@@ -1,61 +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 HWP
-
-   class Property
-      attr_reader :name, :unit, :value, :kind
-
-      def initialize(xml, name)
-        @name, @kind, @value, @unit = xml['name'], xml['kind'].to_sym, xml['value'], xml['unit']
-        declare_ranges(xml)
-        self
-      end
-
-      def present?
-        ! @value.nil?
-      end
-
-      private
-
-      def declare_ranges(xml)
-        case xml['kind']
-          when 'range' then
-            self.class.instance_eval do
-              attr_reader :range
-            end
-            @range = { :from => xml.xpath('range').first['first'], :to => xml.xpath('range').first['last'] }
-          when 'enum' then
-            self.class.instance_eval do
-              attr_reader :options
-            end
-            @options = xml.xpath('enum/entry').collect { |e| e['value'] }
-        end
-      end
-
-    end
-
-    # FloatProperty is like Property but return value is Float instead of String.
-    class FloatProperty < Property
-      def initialize(xml, name)
-        super(xml, name)
-        @value = @value.to_f if @value
-      end
-    end
-  end
-
-end
diff --git a/client/lib/instance_state.rb b/client/lib/instance_state.rb
deleted file mode 100644
index 6a64f57..0000000
--- a/client/lib/instance_state.rb
+++ /dev/null
@@ -1,44 +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 InstanceState
-
-    class State
-      attr_reader :name
-      attr_reader :transitions
-
-      def initialize(name)
-        @name, @transitions = name, []
-      end
-    end
-
-    class Transition
-      attr_reader :to
-      attr_reader :action
-
-      def initialize(to, action)
-        @to = to
-        @action = action
-      end
-
-      def auto?
-        @action.nil?
-      end
-    end
-
-  end
-
-end
diff --git a/client/lib/string.rb b/client/lib/string.rb
deleted file mode 100644
index fb90564..0000000
--- a/client/lib/string.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 String
-
-  unless method_defined?(:classify)
-    # Create a class name from string
-    def classify
-      self.singularize.camelize
-    end
-  end
-
-  unless method_defined?(:camelize)
-    # Camelize converts strings to UpperCamelCase
-    def camelize
-      self.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
-    end
-  end
-
-  unless method_defined?(:singularize)
-    # Strip 's' character from end of string
-    def singularize
-      self.gsub(/s$/, '')
-    end
-  end
-
-  unless method_defined?(:pluralize)
-    def pluralize
-      return self + 'es' if self =~ /ess$/
-      return self[0, self.length-1] + "ies" if self =~ /ty$/
-      return self if self =~ /data$/
-      self + "s"
-    end
-  end
-
-  # Convert string to float if string value seems like Float
-  def convert
-    return self.to_f if self.strip =~ /^([\d\.]+$)/
-    self
-  end
-
-  # Simply converts whitespaces and - symbols to '_' which is safe for Ruby
-  def sanitize
-    self.strip.gsub(/(\W+)/, '_')
-  end
-
-end
diff --git a/client/support/method_test_template.erb b/client/support/method_test_template.erb
new file mode 100644
index 0000000..89831fb
--- /dev/null
+++ b/client/support/method_test_template.erb
@@ -0,0 +1,53 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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 '../test_helper'
+
+describe Deltacloud::Client::Methods::<%=name.to_s.camelize%> do
+
+  before do
+    VCR.insert_cassette(__name__)
+    @client = new_client
+  end
+
+  after do
+    VCR.eject_cassette
+  end
+
+  it 'supports #<%=name.to_s.pluralize%>' do
+    @client.must_respond_to :<%=name.to_s.pluralize%>
+    @client.<%=name.to_s.pluralize%>.must_be_kind_of Array
+    @client.<%=name.to_s.pluralize%>.each { |r| r.must_be_instance_of Deltacloud::Client::<%=name.to_s.camelize%> }
+  end
+
+  it 'supports filtering #<%=name.to_s.pluralize%> by :id param' do
+    result = @client.<%=name.to_s.pluralize%>(:id => 'XXX')
+    result.must_be_kind_of Array
+    result.size.must_equal 1
+    result.first.must_be_instance_of Deltacloud::Client::<%=name.to_s.camelize%>
+    result = @client.<%=name.to_s.pluralize%>(:id => 'unknown')
+    result.must_be_kind_of Array
+    result.size.must_equal 0
+  end
+
+  it 'support #<%=name.to_s%>' do
+    @client.must_respond_to :<%=name%>
+    result = @client.<%=name%>('XXX')
+    result.must_be_instance_of Deltacloud::Client::<%=name.to_s.camelize%>
+    lambda { @client.<%=name%>(nil) }.must_raise Deltacloud::Client::NotFound
+    lambda { @client.<%=name%>('foo') }.must_raise Deltacloud::Client::NotFound
+  end
+
+end
diff --git a/client/support/methods_template.erb b/client/support/methods_template.erb
new file mode 100644
index 0000000..b64b1eb
--- /dev/null
+++ b/client/support/methods_template.erb
@@ -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::Client
+  module Methods
+    module <%=name.to_s.camelize%>
+
+      # Retrieve list of all <%=name%> entities
+      #
+      # Filter options:
+      #
+      # - :id -> Filter entities using 'id' attribute
+      #
+      def <%=name.to_s.pluralize%>(filter_opts={})
+        from_collection :<%=name.to_s.pluralize%>,
+        connection.get(api_uri('<%=name.to_s.pluralize%>'), filter_opts)
+      end
+
+      # Retrieve the single <%=name%> entity
+      #
+      # - <%=name%>_id -> <%=name.to_s.camelize%> entity to retrieve
+      #
+      def <%=name%>(<%=name%>_id)
+        from_resource :<%=name%>,
+          connection.get(api_uri("<%=name.to_s.pluralize%>/#{<%=name%>_id}"))
+      end
+
+      # Create a new <%=name%>
+      #
+      # - create_opts
+      #
+      # def create_<%=name%>(create_opts={})
+      #   must_support! :<%=name.to_s.pluralize%>
+      #    response = connection.post(api_uri('<%=name.to_s.pluralize%>')) do |request|
+      #     request.params = create_opts
+      #   end
+      #   model(:<%=name%>).convert(self, response.body)
+      # end
+
+    end
+  end
+end
diff --git a/client/support/model_template.erb b/client/support/model_template.erb
new file mode 100644
index 0000000..0def783
--- /dev/null
+++ b/client/support/model_template.erb
@@ -0,0 +1,45 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# 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::Client
+  class <%=name.to_s.camelize%> < Base
+
+    include Deltacloud::Client::Methods::<%=name.to_s.camelize%>
+
+    # Inherited attributes: :_id, :name, :description
+
+    # Custom attributes:
+    #
+    # attr_reader :state
+    # attr_reader :realm_id
+
+    # <%=name.to_s.camelize%> model methods
+    #
+    # def reboot!
+    #   <%=name%>_reboot(_id)
+    # end
+
+    # Parse the <%=name.to_s.camelize %> entity from XML body
+    #
+    # - xml_body -> Deltacloud API XML representation of the <%=name%>
+    #
+    def self.parse(xml_body)
+      {
+        # :state => xml_body.text_at(:state),
+        # :realm_id => xml_body.attr_at('realm', :id)
+      }
+    end
+  end
+end
-- 
1.8.1.4


Mime
View raw message