You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltacloud.apache.org by mf...@apache.org on 2013/03/26 18:57:48 UTC

[02/30] Client: Complete rewrite of deltacloud-client

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/driver.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/firewall.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/hardware_profile.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/image.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/instance.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/instance_state.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/key.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/realm.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/storage_snapshot.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/methods/storage_volume.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models.rb
----------------------------------------------------------------------
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'

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/address.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/base.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/blob.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/bucket.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/driver.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/firewall.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/hardware_profile.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/image.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/instance.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/instance_address.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/instance_state.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/key.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/realm.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/storage_snapshot.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/client/models/storage_volume.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/core_ext.rb
----------------------------------------------------------------------
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'

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/core_ext/element.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/core_ext/fixnum.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/core_ext/nil.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/core_ext/string.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/deltacloud/error_response.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/documentation.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/errors.rb
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/deltacloud/blob/b6d3365c/client/lib/hwp_properties.rb
----------------------------------------------------------------------
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