You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by ts...@redhat.com on 2010/10/11 14:29:55 UTC

Fix for HTTP redirects in the deltacloud-client

Hey all,

The current version of deltacloud-client doesn't support HTTP redirects. When
you do

    DeltaCloud.new('mockuser', 'mockpassword', 'http://localhost:3001')

with `deltacloudd -i mock` listening on the port 3001, the connection will
fail, because the client doesn't proces the response properly.

(note that the mock server redirects '/' to '/api')

These two patches add tests for this and implement a solution.

[PATCH 1/2] Add tests for URLs that return HTTP redirect
[PATCH 2/2] Follow HTTP redirects for API URLs in the client

Please let me know what you think and chew me up if you can find a better
solution -- I'm not very familiar with the codebase.

Cheers,
Tomas Sedovic

[PATCH 1/2] Add tests for URLs that return HTTP redirect

Posted by ts...@redhat.com.
From: Tomas Sedovic <ts...@redhat.com>

---
 client/specs/hardware_profiles_spec.rb |   16 +++++++-----
 client/specs/images_spec.rb            |   28 +++++++++++----------
 client/specs/initialization_spec.rb    |   14 ++++++----
 client/specs/instance_states_spec.rb   |   30 ++++++++++++----------
 client/specs/instances_spec.rb         |   42 ++++++++++++++++---------------
 client/specs/realms_spec.rb            |   22 +++++++++-------
 client/specs/spec_helper.rb            |    1 +
 client/specs/storage_snapshot_spec.rb  |   20 ++++++++-------
 client/specs/storage_volume_spec.rb    |   20 ++++++++-------
 9 files changed, 105 insertions(+), 88 deletions(-)

diff --git a/client/specs/hardware_profiles_spec.rb b/client/specs/hardware_profiles_spec.rb
index 026b146..d11eb36 100644
--- a/client/specs/hardware_profiles_spec.rb
+++ b/client/specs/hardware_profiles_spec.rb
@@ -31,13 +31,15 @@ describe "hardware_profiles" do
   it_should_behave_like "all resources"
 
   it "should allow retrieval of all hardware profiles" do
-    DeltaCloud.new( API_NAME, API_PASSWORD, API_URL ) do |client|
-      hardware_profiles = client.hardware_profiles
-      hardware_profiles.should_not be_empty
-      hardware_profiles.each do |hwp|
-        hwp.uri.should_not be_nil
-        hwp.uri.should be_a(String)
-        prop_check(hwp.architecture, String)  if hwp.architecture
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      DeltaCloud.new( API_NAME, API_PASSWORD, entry_point ) do |client|
+        hardware_profiles = client.hardware_profiles
+        hardware_profiles.should_not be_empty
+        hardware_profiles.each do |hwp|
+          hwp.uri.should_not be_nil
+          hwp.uri.should be_a(String)
+          prop_check(hwp.architecture, String)  if hwp.architecture
+        end
       end
     end
   end
diff --git a/client/specs/images_spec.rb b/client/specs/images_spec.rb
index abdc5ee..3b209cd 100644
--- a/client/specs/images_spec.rb
+++ b/client/specs/images_spec.rb
@@ -24,19 +24,21 @@ describe "images" do
   it_should_behave_like "all resources"
 
   it "should allow retrieval of all images" do
-    DeltaCloud.new( API_NAME, API_PASSWORD, API_URL ) do |client|
-      images = client.images
-      images.should_not be_empty
-      images.size.should eql( 3 )
-      images.each do |image|
-        image.uri.should_not be_nil
-        image.uri.should be_a(String)
-        image.description.should_not be_nil
-        image.description.should be_a(String)
-        image.architecture.should_not be_nil
-        image.architecture.should be_a(String)
-        image.owner_id.should_not be_nil
-        image.owner_id.should be_a(String)
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      DeltaCloud.new( API_NAME, API_PASSWORD, entry_point ) do |client|
+        images = client.images
+        images.should_not be_empty
+        images.size.should eql( 3 )
+        images.each do |image|
+          image.uri.should_not be_nil
+          image.uri.should be_a(String)
+          image.description.should_not be_nil
+          image.description.should be_a(String)
+          image.architecture.should_not be_nil
+          image.architecture.should be_a(String)
+          image.owner_id.should_not be_nil
+          image.owner_id.should be_a(String)
+        end
       end
     end
   end
diff --git a/client/specs/initialization_spec.rb b/client/specs/initialization_spec.rb
index 4f53317..672d858 100644
--- a/client/specs/initialization_spec.rb
+++ b/client/specs/initialization_spec.rb
@@ -28,12 +28,14 @@ describe "initializing the client" do
   end
 
   it "should discover entry points upon connection" do
-    DeltaCloud.new( "name", "password", API_URL ) do |client|
-      client.entry_points[:hardware_profiles].should eql( "#{API_URL}/hardware_profiles" )
-      client.entry_points[:images].should            eql( "#{API_URL}/images" )
-      client.entry_points[:instances].should         eql( "#{API_URL}/instances" )
-      client.entry_points[:storage_volumes].should   eql( "#{API_URL}/storage_volumes" )
-      client.entry_points[:storage_snapshots].should eql( "#{API_URL}/storage_snapshots" )
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      DeltaCloud.new( "name", "password", entry_point ) do |client|
+        client.entry_points[:hardware_profiles].should eql( "#{API_URL}/hardware_profiles" )
+        client.entry_points[:images].should            eql( "#{API_URL}/images" )
+        client.entry_points[:instances].should         eql( "#{API_URL}/instances" )
+        client.entry_points[:storage_volumes].should   eql( "#{API_URL}/storage_volumes" )
+        client.entry_points[:storage_snapshots].should eql( "#{API_URL}/storage_snapshots" )
+      end
     end
   end
 
diff --git a/client/specs/instance_states_spec.rb b/client/specs/instance_states_spec.rb
index 49b5a35..c79c273 100644
--- a/client/specs/instance_states_spec.rb
+++ b/client/specs/instance_states_spec.rb
@@ -33,23 +33,25 @@ describe "instance-states" do
   it_should_behave_like "all resources"
 
   it "should allow retrieval of instance-state information" do
-    DeltaCloud.new( API_NAME, API_PASSWORD, API_URL ) do |client|
-      instance_states = client.instance_states
-      instance_states.should_not be_nil
-      instance_states.should_not be_empty
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      DeltaCloud.new( API_NAME, API_PASSWORD, entry_point ) do |client|
+        instance_states = client.instance_states
+        instance_states.should_not be_nil
+        instance_states.should_not be_empty
 
-      instance_states[0].name.should eql( 'start' )
-      instance_states[0].transitions.size.should eql( 1 )
-      instance_states[0].transitions[0].should_not be_auto
+        instance_states[0].name.should eql( 'start' )
+        instance_states[0].transitions.size.should eql( 1 )
+        instance_states[0].transitions[0].should_not be_auto
 
-      instance_states[1].name.should eql( 'pending' )
-      instance_states[1].transitions.size.should eql( 1 )
-      instance_states[1].transitions[0].should be_auto
+        instance_states[1].name.should eql( 'pending' )
+        instance_states[1].transitions.size.should eql( 1 )
+        instance_states[1].transitions[0].should be_auto
 
-      instance_states[2].name.should eql( 'running' )
-      instance_states[2].transitions.size.should eql( 2 )
-      includes_transition( instance_states[2].transitions, :reboot, :running ).should be_true
-      includes_transition( instance_states[2].transitions, :stop, :stopped ).should be_true
+        instance_states[2].name.should eql( 'running' )
+        instance_states[2].transitions.size.should eql( 2 )
+        includes_transition( instance_states[2].transitions, :reboot, :running ).should be_true
+        includes_transition( instance_states[2].transitions, :stop, :stopped ).should be_true
+      end
     end
   end
 
diff --git a/client/specs/instances_spec.rb b/client/specs/instances_spec.rb
index 8729cc0..c4995ae 100644
--- a/client/specs/instances_spec.rb
+++ b/client/specs/instances_spec.rb
@@ -24,26 +24,28 @@ describe "instances" do
   it_should_behave_like "all resources"
 
   it "should allow retrieval of all instances" do
-    DeltaCloud.new( API_NAME, API_PASSWORD, API_URL ) do |client|
-      instances = client.instances
-      instances.should_not be_empty
-      instances.each do |instance|
-        instance.uri.should_not be_nil
-        instance.uri.should be_a( String )
-        instance.owner_id.should_not be_nil
-        instance.owner_id.should be_a( String )
-        instance.image.should_not be_nil
-        instance.image.should be_a( DeltaCloud::API::Image )
-        instance.hardware_profile.should_not be_nil
-        instance.hardware_profile.should be_a( DeltaCloud::API::HardwareProfile )
-        instance.state.should_not be_nil
-        instance.state.should be_a( String )
-        instance.public_addresses.should_not be_nil
-        instance.public_addresses.should_not be_empty
-        instance.public_addresses.should be_a( Array )
-        instance.private_addresses.should_not be_nil
-        instance.private_addresses.should_not be_empty
-        instance.private_addresses.should be_a( Array )
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      DeltaCloud.new( API_NAME, API_PASSWORD, entry_point ) do |client|
+        instances = client.instances
+        instances.should_not be_empty
+        instances.each do |instance|
+          instance.uri.should_not be_nil
+          instance.uri.should be_a( String )
+          instance.owner_id.should_not be_nil
+          instance.owner_id.should be_a( String )
+          instance.image.should_not be_nil
+          instance.image.should be_a( DeltaCloud::API::Image )
+          instance.hardware_profile.should_not be_nil
+          instance.hardware_profile.should be_a( DeltaCloud::API::HardwareProfile )
+          instance.state.should_not be_nil
+          instance.state.should be_a( String )
+          instance.public_addresses.should_not be_nil
+          instance.public_addresses.should_not be_empty
+          instance.public_addresses.should be_a( Array )
+          instance.private_addresses.should_not be_nil
+          instance.private_addresses.should_not be_empty
+          instance.private_addresses.should be_a( Array )
+        end
       end
     end
   end
diff --git a/client/specs/realms_spec.rb b/client/specs/realms_spec.rb
index 8b1175a..241fb5c 100644
--- a/client/specs/realms_spec.rb
+++ b/client/specs/realms_spec.rb
@@ -23,16 +23,18 @@ describe "realms" do
   it_should_behave_like "all resources"
 
   it "should allow retrieval of all realms" do
-    DeltaCloud.new( API_NAME, API_PASSWORD, API_URL ) do |client|
-      realms = client.realms
-      realms.should_not be_empty
-      realms.each do |realm|
-        realm.uri.should_not be_nil
-        realm.uri.should be_a(String)
-        realm.id.should_not be_nil
-        realm.id.should be_a(String)
-        realm.name.should_not be_nil
-        realm.name.should be_a(String)
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      DeltaCloud.new( API_NAME, API_PASSWORD, entry_point ) do |client|
+        realms = client.realms
+        realms.should_not be_empty
+        realms.each do |realm|
+          realm.uri.should_not be_nil
+          realm.uri.should be_a(String)
+          realm.id.should_not be_nil
+          realm.id.should be_a(String)
+          realm.name.should_not be_nil
+          realm.name.should be_a(String)
+        end
       end
     end
   end
diff --git a/client/specs/spec_helper.rb b/client/specs/spec_helper.rb
index 81ee943..b4cb95c 100644
--- a/client/specs/spec_helper.rb
+++ b/client/specs/spec_helper.rb
@@ -33,6 +33,7 @@ API_PORT = api_port
 API_PATH = '/api'
 
 API_URL = "http://#{API_HOST}:#{API_PORT}#{API_PATH}"
+API_URL_REDIRECT = "http://#{API_HOST}:#{API_PORT}"
 API_NAME     = 'mockuser'
 API_PASSWORD = 'mockpassword'
 
diff --git a/client/specs/storage_snapshot_spec.rb b/client/specs/storage_snapshot_spec.rb
index 8281871..f1ae43b 100644
--- a/client/specs/storage_snapshot_spec.rb
+++ b/client/specs/storage_snapshot_spec.rb
@@ -24,15 +24,17 @@ describe "storage snapshot" do
   it_should_behave_like "all resources"
 
   it "allow retrieval of all storage volumes owned by the current user" do
-    client = DeltaCloud.new( API_NAME, API_PASSWORD, API_URL )
-    client.connect do |client|
-      storage_snapshots = client.storage_snapshots
-      storage_snapshots.should_not be_nil
-      storage_snapshots.should_not be_empty
-      ids = storage_snapshots.collect{|e| e.id}
-      ids.size.should eql( 2 )
-      ids.should include( 'snap2' )
-      ids.should include( 'snap3' )
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      client = DeltaCloud.new( API_NAME, API_PASSWORD, entry_point )
+      client.connect do |client|
+        storage_snapshots = client.storage_snapshots
+        storage_snapshots.should_not be_nil
+        storage_snapshots.should_not be_empty
+        ids = storage_snapshots.collect{|e| e.id}
+        ids.size.should eql( 2 )
+        ids.should include( 'snap2' )
+        ids.should include( 'snap3' )
+      end
     end
   end
 
diff --git a/client/specs/storage_volume_spec.rb b/client/specs/storage_volume_spec.rb
index ab81b62..f57d9c1 100644
--- a/client/specs/storage_volume_spec.rb
+++ b/client/specs/storage_volume_spec.rb
@@ -24,15 +24,17 @@ describe "storage volumes" do
   it_should_behave_like "all resources"
 
   it "allow retrieval of all storage volumes owned by the current user" do
-    client = DeltaCloud.new( API_NAME, API_PASSWORD, API_URL )
-    client.connect do |client|
-      storage_volumes = client.storage_volumes
-      storage_volumes.should_not be_nil
-      storage_volumes.should_not be_empty
-      ids = storage_volumes.collect{|e| e.id}
-      ids.size.should eql( 2 )
-      ids.should include( 'vol2' )
-      ids.should include( 'vol3' )
+    [API_URL, API_URL_REDIRECT].each do |entry_point|
+      client = DeltaCloud.new( API_NAME, API_PASSWORD, entry_point )
+      client.connect do |client|
+        storage_volumes = client.storage_volumes
+        storage_volumes.should_not be_nil
+        storage_volumes.should_not be_empty
+        ids = storage_volumes.collect{|e| e.id}
+        ids.size.should eql( 2 )
+        ids.should include( 'vol2' )
+        ids.should include( 'vol3' )
+      end
     end
   end
 
-- 
1.7.2.3


[PATCH 2/2] Follow HTTP redirects for API URLs in the client

Posted by ts...@redhat.com.
From: Tomas Sedovic <ts...@redhat.com>

---
 client/lib/deltacloud.rb |   20 +++++++++++++++-----
 1 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/client/lib/deltacloud.rb b/client/lib/deltacloud.rb
index 40da4ad..117a04b 100644
--- a/client/lib/deltacloud.rb
+++ b/client/lib/deltacloud.rb
@@ -105,7 +105,7 @@ module DeltaCloud
       API.instance_eval do
         entry_points.keys.select {|k| [:instance_states].include?(k)==false }.each do |model|
           define_method model do |*args|
-            request(:get, "/#{model}", args.first) do |response|
+            request(:get, entry_points[model], args.first) do |response|
               # Define a new class based on model name
               c = DeltaCloud.define_class("#{model.to_s.classify}")
               # Create collection from index operation
@@ -114,7 +114,7 @@ module DeltaCloud
           end
           logger << "[API] Added method #{model}\n"
           define_method :"#{model.to_s.singularize}" do |*args|
-            request(:get, "/#{model}/#{args[0]}") do |response|
+            request(:get, "#{entry_points[model]}/#{args[0]}") do |response|
               # Define a new class based on model name
               c = DeltaCloud.define_class("#{model.to_s.classify}")
               # Build class for returned object
@@ -344,10 +344,20 @@ module DeltaCloud
         end
       else
         RestClient.send(conf[:method], conf[:path], default_headers) do |response, request, block|
-          if response.respond_to?('body')
-            yield response.body if block_given?
+          if conf[:method].eql?(:get) and [301, 302, 307].include? response.code
+            response.follow_redirection(request) do |response, request, block|
+              if response.respond_to?('body')
+                yield response.body if block_given?
+              else
+                yield response.to_s if block_given?
+              end
+            end
           else
-            yield response.to_s if block_given?
+            if response.respond_to?('body')
+              yield response.body if block_given?
+            else
+              yield response.to_s if block_given?
+            end
           end
         end
       end
-- 
1.7.2.3


Re: Fix for HTTP redirects in the deltacloud-client

Posted by Michal Fojtik <mf...@redhat.com>.
On 11/10/10 14:29 +0200, tsedovic@redhat.com wrote:

ACK. Nice catch Tomas. Tested && Pushed.

>Hey all,
>
>The current version of deltacloud-client doesn't support HTTP redirects. When
>you do
>
>    DeltaCloud.new('mockuser', 'mockpassword', 'http://localhost:3001')
>
>with `deltacloudd -i mock` listening on the port 3001, the connection will
>fail, because the client doesn't proces the response properly.
>
>(note that the mock server redirects '/' to '/api')
>
>These two patches add tests for this and implement a solution.
>
>[PATCH 1/2] Add tests for URLs that return HTTP redirect
>[PATCH 2/2] Follow HTTP redirects for API URLs in the client
>
>Please let me know what you think and chew me up if you can find a better
>solution -- I'm not very familiar with the codebase.
>
>Cheers,
>Tomas Sedovic

-- 
--------------------------------------------------------
Michal Fojtik, mfojtik@redhat.com
Deltacloud API: http://deltacloud.org
--------------------------------------------------------