From c5446107911f8164673a87b4f56f41bc75f1e216 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Sun, 9 Dec 2012 16:51:07 -0500 Subject: [PATCH 1/2] OpenStack custom exception cleanup. Fixes an exception class name error for the custom OpenStack ServiceUnavailable exception. Previously the wrong class name was being used. Also cleans up and simplifies some other exceptions in the OpenStack implementation. (We can simply use NotFound from Fog::Errors instead) --- lib/fog/openstack.rb | 9 +++------ lib/fog/openstack/compute.rb | 3 ++- tests/openstack/authenticate_tests.rb | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/fog/openstack.rb b/lib/fog/openstack.rb index fe183789b..0cf9b1a97 100644 --- a/lib/fog/openstack.rb +++ b/lib/fog/openstack.rb @@ -26,9 +26,6 @@ module Fog end end - class InternalServerError < ServiceError; end - class Conflict < ServiceError; end - class NotFound < ServiceError; end class ServiceUnavailable < ServiceError; end class BadRequest < ServiceError @@ -103,7 +100,7 @@ module Fog body = Fog::JSON.decode(response.body) if body['tenants'].empty? - raise Errors::NotFound.new('No Tenant Found') + raise Fog::Errors::NotFound.new('No Tenant Found') else options[:openstack_tenant] = body['tenants'].first['name'] end @@ -127,12 +124,12 @@ module Fog message = "Could not find service #{missing}. Have #{available}" - raise Errors::NotFound, message + raise Fog::Errors::NotFound, message end if service['endpoints'].count > 1 regions = service["endpoints"].map{ |e| e['region'] }.uniq.join(',') - raise Errors::NotFound.new("Multiple regions available choose one of these '#{regions}'") + raise Fog::Errors::NotFound.new("Multiple regions available choose one of these '#{regions}'") end identity_service = body['access']['serviceCatalog']. diff --git a/lib/fog/openstack/compute.rb b/lib/fog/openstack/compute.rb index 9539cbb54..1efc9bbc1 100644 --- a/lib/fog/openstack/compute.rb +++ b/lib/fog/openstack/compute.rb @@ -372,6 +372,7 @@ module Fog } if @openstack_auth_uri.path =~ /\/v2.0\// + credentials = Fog::OpenStack.authenticate_v2(options, @connection_options) else credentials = Fog::OpenStack.authenticate_v1(options, @connection_options) @@ -393,7 +394,7 @@ module Fog @path.sub!(/\/$/, '') unless @path.match(/1\.1|v2/) - raise Fog::Compute::OpenStack::ServiceUnavailable.new( + raise Fog::OpenStack::Errors::ServiceUnavailable.new( "OpenStack binding only supports version 2 (a.k.a. 1.1)") end diff --git a/tests/openstack/authenticate_tests.rb b/tests/openstack/authenticate_tests.rb index 55490f599..38dd519a0 100644 --- a/tests/openstack/authenticate_tests.rb +++ b/tests/openstack/authenticate_tests.rb @@ -93,7 +93,7 @@ Shindo.tests('OpenStack | authenticate', ['openstack']) do Excon.stub({ :method => 'POST', :path => "/v2.0/tokens" }, { :status => 200, :body => Fog::JSON.encode(body) }) - raises(Fog::OpenStack::Errors::NotFound, + raises(Fog::Errors::NotFound, 'Could not find service network. Have compute, image') do Fog::OpenStack.authenticate_v2( :openstack_auth_uri => URI('http://example/v2.0/tokens'), From ba2612900164ffa770a71e704a2d22b4a37680c2 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 10 Dec 2012 07:55:54 -0500 Subject: [PATCH 2/2] OpenStack auth updates to select by service name. This patch updates the OpenStack auth implementation so that it supports selecting API service by both 'name' and 'type'. Previously the implementation was confusing because it used a config param called :openstack_service_name to select the service 'type' from the catalog. This patch swaps it so that :openstack_service_name actually selects by 'name'. The previous logic to select service by type ('compute' for example) has been preserved in a new :openstack_service_type parameter. This option is used just as it was before for backwards compatability. This change is potentially breaking for anyone previously using :openstack_service_name (which I don't think is that common but is possible). As such we should probably make a release note saying that previous users of :openstack_service_name should migrate to use :openstack_service_type instead. --- lib/fog/openstack.rb | 26 +++++++++++++------ lib/fog/openstack/compute.rb | 22 +++++++++++----- lib/fog/openstack/identity.rb | 6 +++-- lib/fog/openstack/image.rb | 6 +++-- lib/fog/openstack/network.rb | 8 +++--- lib/fog/openstack/volume.rb | 6 +++-- tests/openstack/authenticate_tests.rb | 37 +++++++++++++++++++++++++-- 7 files changed, 85 insertions(+), 26 deletions(-) diff --git a/lib/fog/openstack.rb b/lib/fog/openstack.rb index 0cf9b1a97..4b014d386 100644 --- a/lib/fog/openstack.rb +++ b/lib/fog/openstack.rb @@ -74,15 +74,15 @@ module Fog def self.authenticate_v2(options, connection_options = {}) uri = options[:openstack_auth_uri] tenant_name = options[:openstack_tenant] + service_type = options[:openstack_service_type] service_name = options[:openstack_service_name] - identity_service_name = options[:openstack_identity_service_name] + identity_service_type = options[:openstack_identity_service_type] endpoint_type = (options[:openstack_endpoint_type] || 'publicURL').to_s openstack_region = options[:openstack_region] body = retrieve_tokens_v2(options, connection_options) - service = body['access']['serviceCatalog']. - detect {|s| service_name.include?(s['type']) } + service = get_service(body, service_type, service_name) options[:unscoped_token] = body['access']['token']['id'] @@ -107,8 +107,8 @@ module Fog end body = retrieve_tokens_v2(options, connection_options) - service = body['access']['serviceCatalog']. - detect{|s| service_name.include?(s['type']) } + service = get_service(body, service_type, service_name) + end service['endpoints'] = service['endpoints'].select do |endpoint| @@ -120,7 +120,7 @@ module Fog endpoint['type'] }.sort.join ', ' - missing = service_name.join ', ' + missing = service_type.join ', ' message = "Could not find service #{missing}. Have #{available}" @@ -132,8 +132,7 @@ module Fog raise Fog::Errors::NotFound.new("Multiple regions available choose one of these '#{regions}'") end - identity_service = body['access']['serviceCatalog']. - detect{|x| identity_service_name.include?(x['type']) } if identity_service_name + identity_service = get_service(body, identity_service_type) if identity_service_type tenant = body['access']['token']['tenant'] user = body['access']['user'] @@ -150,6 +149,17 @@ module Fog :current_user_id => body['access']['user']['id'], :unscoped_token => options[:unscoped_token] } + + end + + def self.get_service(body, service_type=[], service_name=nil) + body['access']['serviceCatalog'].detect do |s| + if service_name.nil? or service_name.empty? + service_type.include?(s['type']) + else + service_type.include?(s['type']) and s['name'] == service_name + end + end end def self.retrieve_tokens_v2(options, connection_options = {}) diff --git a/lib/fog/openstack/compute.rb b/lib/fog/openstack/compute.rb index 1efc9bbc1..c5adfd2fb 100644 --- a/lib/fog/openstack/compute.rb +++ b/lib/fog/openstack/compute.rb @@ -7,7 +7,8 @@ module Fog requires :openstack_auth_url recognizes :openstack_auth_token, :openstack_management_url, - :persistent, :openstack_service_name, :openstack_tenant, + :persistent, :openstack_service_type, :openstack_service_name, + :openstack_tenant, :openstack_api_key, :openstack_username, :openstack_identity_endpoint, :current_user, :current_tenant, :openstack_region @@ -290,8 +291,9 @@ module Fog @openstack_auth_uri = URI.parse(options[:openstack_auth_url]) @openstack_management_url = options[:openstack_management_url] @openstack_must_reauthenticate = false - @openstack_service_name = options[:openstack_service_name] || ['nova', 'compute'] - @openstack_identity_service_name = options[:openstack_identity_service_name] || 'identity' + @openstack_service_type = options[:openstack_service_type] || ['nova', 'compute'] + @openstack_service_name = options[:openstack_service_name] + @openstack_identity_service_type = options[:openstack_identity_service_type] || 'identity' @openstack_region = options[:openstack_region] @connection_options = options[:connection_options] || {} @@ -367,8 +369,9 @@ module Fog :openstack_auth_uri => @openstack_auth_uri, :openstack_region => @openstack_region, :openstack_tenant => @openstack_tenant, + :openstack_service_type => @openstack_service_type, :openstack_service_name => @openstack_service_name, - :openstack_identity_service_name => @openstack_identity_service_name + :openstack_identity_service_type => @openstack_identity_service_type } if @openstack_auth_uri.path =~ /\/v2.0\// @@ -400,9 +403,14 @@ module Fog @port = uri.port @scheme = uri.scheme - @identity_connection = Fog::Connection.new( - @openstack_identity_public_endpoint, - false, @connection_options) + + # Not all implementations have identity service in the catalog + if @openstack_identity_public_endpoint + @identity_connection = Fog::Connection.new( + @openstack_identity_public_endpoint, + false, @connection_options) + end + true end diff --git a/lib/fog/openstack/identity.rb b/lib/fog/openstack/identity.rb index 808288a99..ec80e9ad3 100644 --- a/lib/fog/openstack/identity.rb +++ b/lib/fog/openstack/identity.rb @@ -6,7 +6,7 @@ module Fog requires :openstack_auth_url recognizes :openstack_auth_token, :openstack_management_url, :persistent, - :openstack_service_name, :openstack_tenant, + :openstack_service_type, :openstack_service_name, :openstack_tenant, :openstack_api_key, :openstack_username, :openstack_current_user_id, :current_user, :current_tenant @@ -186,7 +186,8 @@ module Fog @openstack_auth_uri = URI.parse(options[:openstack_auth_url]) @openstack_management_url = options[:openstack_management_url] @openstack_must_reauthenticate = false - @openstack_service_name = options[:openstack_service_name] || ['identity'] + @openstack_service_type = options[:openstack_service_type] || ['identity'] + @openstack_service_name = options[:openstack_service_name] @connection_options = options[:connection_options] || {} @@ -260,6 +261,7 @@ module Fog :openstack_auth_token => @openstack_auth_token, :openstack_auth_uri => @openstack_auth_uri, :openstack_tenant => @openstack_tenant, + :openstack_service_type => @openstack_service_type, :openstack_service_name => @openstack_service_name, :openstack_endpoint_type => 'adminURL' } diff --git a/lib/fog/openstack/image.rb b/lib/fog/openstack/image.rb index f822e4b10..deb928ca3 100644 --- a/lib/fog/openstack/image.rb +++ b/lib/fog/openstack/image.rb @@ -5,7 +5,7 @@ module Fog class OpenStack < Fog::Service requires :openstack_auth_url recognizes :openstack_auth_token, :openstack_management_url, :persistent, - :openstack_service_name, :openstack_tenant, + :openstack_service_type, :openstack_service_name, :openstack_tenant, :openstack_api_key, :openstack_username, :current_user, :current_tenant @@ -109,7 +109,8 @@ module Fog @openstack_auth_uri = URI.parse(options[:openstack_auth_url]) @openstack_management_url = options[:openstack_management_url] @openstack_must_reauthenticate = false - @openstack_service_name = options[:openstack_service_name] || ['image'] + @openstack_service_type = options[:openstack_service_type] || ['image'] + @openstack_service_name = options[:openstack_service_name] @connection_options = options[:connection_options] || {} @@ -179,6 +180,7 @@ module Fog :openstack_username => @openstack_username, :openstack_auth_uri => @openstack_auth_uri, :openstack_auth_token => @openstack_auth_token, + :openstack_service_type => @openstack_service_type, :openstack_service_name => @openstack_service_name, :openstack_endpoint_type => 'adminURL' } diff --git a/lib/fog/openstack/network.rb b/lib/fog/openstack/network.rb index 4ef057137..19db65439 100644 --- a/lib/fog/openstack/network.rb +++ b/lib/fog/openstack/network.rb @@ -6,7 +6,7 @@ module Fog requires :openstack_auth_url recognizes :openstack_auth_token, :openstack_management_url, :persistent, - :openstack_service_name, :openstack_tenant, + :openstack_service_type, :openstack_service_name, :openstack_tenant, :openstack_api_key, :openstack_username, :current_user, :current_tenant @@ -107,7 +107,8 @@ module Fog @openstack_auth_uri = URI.parse(options[:openstack_auth_url]) @openstack_management_url = options[:openstack_management_url] @openstack_must_reauthenticate = false - @openstack_service_name = options[:openstack_service_name] || ['network'] + @openstack_service_type = options[:openstack_service_type] || ['network'] + @openstack_service_name = options[:openstack_service_name] @connection_options = options[:connection_options] || {} @@ -178,6 +179,7 @@ module Fog :openstack_username => @openstack_username, :openstack_auth_uri => @openstack_auth_uri, :openstack_auth_token => @openstack_auth_token, + :openstack_service_type => @openstack_service_type, :openstack_service_name => @openstack_service_name, :openstack_endpoint_type => 'adminURL' } @@ -231,4 +233,4 @@ module Fog end end end -end \ No newline at end of file +end diff --git a/lib/fog/openstack/volume.rb b/lib/fog/openstack/volume.rb index e3c1629d9..5542aa972 100644 --- a/lib/fog/openstack/volume.rb +++ b/lib/fog/openstack/volume.rb @@ -6,7 +6,7 @@ module Fog requires :openstack_auth_url recognizes :openstack_auth_token, :openstack_management_url, :persistent, - :openstack_service_name, :openstack_tenant, + :openstack_service_type, :openstack_service_name, :openstack_tenant, :openstack_api_key, :openstack_username, :current_user, :current_tenant @@ -111,7 +111,8 @@ module Fog @openstack_auth_uri = URI.parse(options[:openstack_auth_url]) @openstack_management_url = options[:openstack_management_url] @openstack_must_reauthenticate = false - @openstack_service_name = options[:openstack_service_name] || ['volume'] + @openstack_service_type = options[:openstack_service_type] || ['volume'] + @openstack_service_name = options[:openstack_service_name] @connection_options = options[:connection_options] || {} @@ -182,6 +183,7 @@ module Fog :openstack_username => @openstack_username, :openstack_auth_uri => @openstack_auth_uri, :openstack_auth_token => @openstack_auth_token, + :openstack_service_type => @openstack_service_type, :openstack_service_name => @openstack_service_name, :openstack_endpoint_type => 'adminURL' } diff --git a/tests/openstack/authenticate_tests.rb b/tests/openstack/authenticate_tests.rb index 38dd519a0..14bc75c88 100644 --- a/tests/openstack/authenticate_tests.rb +++ b/tests/openstack/authenticate_tests.rb @@ -85,7 +85,7 @@ Shindo.tests('OpenStack | authenticate', ['openstack']) do Fog::OpenStack.authenticate_v2( :openstack_auth_uri => URI('http://example/v2.0/tokens'), :openstack_tenant => 'admin', - :openstack_service_name => %w[compute]) + :openstack_service_type => %w[compute]) end end @@ -98,9 +98,42 @@ Shindo.tests('OpenStack | authenticate', ['openstack']) do Fog::OpenStack.authenticate_v2( :openstack_auth_uri => URI('http://example/v2.0/tokens'), :openstack_tenant => 'admin', - :openstack_service_name => %w[network]) + :openstack_service_type => %w[network]) end end + + tests("v2 auth with two compute services") do + body_clone = body.clone + body_clone["access"]["serviceCatalog"] << + { + "endpoints" => [{ + "adminURL" => + "http://example2:8774/v2/#{tenant_token}", + "region" => "RegionOne", + "internalURL" => + "http://example2:8774/v2/#{tenant_token}", + "id" => Fog::Mock.random_numbers(8).to_s, + "publicURL" => + "http://example2:8774/v2/#{tenant_token}" + }], + "endpoints_links" => [], + "type" => "compute", + "name" => "nova2" + } + + Excon.stub({ :method => 'POST', :path => "/v2.0/tokens" }, + { :status => 200, :body => Fog::JSON.encode(body_clone) }) + + returns("http://example2:8774/v2/#{tenant_token}") do + Fog::OpenStack.authenticate_v2( + :openstack_auth_uri => URI('http://example/v2.0/tokens'), + :openstack_tenant => 'admin', + :openstack_service_type => %w[compute], + :openstack_service_name => 'nova2')[:server_management_url] + end + + end + ensure Excon.stubs.clear Excon.defaults[:mock] = @old_mock_value