aviator 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/aviator.gemspec +13 -13
- data/lib/aviator/core/session.rb +234 -30
- data/lib/aviator/openstack/identity/requests/v2/admin/create_user.rb +1 -0
- data/lib/aviator/openstack/identity/requests/v2/admin/update_user.rb +1 -0
- data/lib/aviator/openstack/provider.rb +63 -0
- data/lib/aviator/version.rb +1 -1
- data/test/aviator/core/session_test.rb +331 -176
- data/test/aviator/openstack/identity/requests/v2/admin/create_user_test.rb +2 -1
- data/test/aviator/openstack/identity/requests/v2/admin/update_user_test.rb +2 -1
- data/test/support/dummy/auth/requests/v1/public/authenticate.rb +33 -0
- data/test/support/dummy/auth/requests/v1/public/validate.rb +22 -0
- data/test/support/dummy/common/requests/v0/public/base.rb +18 -0
- data/test/support/dummy/compute/requests/v1/public/create_server.rb +22 -0
- data/test/support/dummy/provider.rb +31 -0
- metadata +80 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f56372f2f4fea06121bebdef1c2bccfef12c1f56
|
4
|
+
data.tar.gz: a17fe8facfb17ba357ceb772d9087e89d53a59ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00aa0e3555582535cfac8d3699259d31140cc88f920f2d162c064d64e2b483ccc8bb484aa29f59f99be99cda355d57a450de29c08714d14e07d23978a9c3a116
|
7
|
+
data.tar.gz: 7a0155396260c67ab9c7f1c0d03504f7a1e81f8e36463b347303198375c0486d415acd5e97d265036a0ac7a7be9878c9d304ee2743d98dd40b6733f594611cef
|
data/Gemfile
CHANGED
data/aviator.gemspec
CHANGED
@@ -22,24 +22,24 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
24
|
# Runtime dependencies
|
25
|
-
spec.
|
26
|
-
spec.
|
27
|
-
spec.
|
25
|
+
spec.add_runtime_dependency 'faraday', '~> 0.8', '>= 0.8.8'
|
26
|
+
spec.add_runtime_dependency 'thor', '~> 0.18', '>= 0.18.1'
|
27
|
+
spec.add_runtime_dependency 'terminal-table', '~> 1.4', '>= 1.4.5'
|
28
28
|
|
29
29
|
# Development dependencies. See Gemfile for more development deps.
|
30
|
-
spec.add_development_dependency
|
31
|
-
spec.add_development_dependency 'rb-fsevent', '~> 0.9.0'
|
32
|
-
spec.add_development_dependency 'guard', '~> 1.8.0'
|
33
|
-
spec.add_development_dependency 'guard-rake', '~> 0.0.0'
|
34
|
-
spec.add_development_dependency 'guard-minitest', '~> 0.5.0'
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.0'
|
31
|
+
spec.add_development_dependency 'rb-fsevent', '~> 0.9', '>= 0.9.0'
|
32
|
+
spec.add_development_dependency 'guard', '~> 1.8', '>= 1.8.0'
|
33
|
+
spec.add_development_dependency 'guard-rake', '~> 0.0', '>= 0.0.0'
|
34
|
+
spec.add_development_dependency 'guard-minitest', '~> 0.5', '>= 0.5.0'
|
35
35
|
|
36
36
|
if /darwin|mac os/ === RbConfig::CONFIG['host_os']
|
37
|
-
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.5.3'
|
37
|
+
spec.add_development_dependency 'terminal-notifier-guard', '~> 1.5', '>= 1.5.3'
|
38
38
|
else
|
39
|
-
spec.add_development_dependency 'ruby_gntp', '~> 0.3.0'
|
39
|
+
spec.add_development_dependency 'ruby_gntp', '~> 0.3', '>= 0.3.0'
|
40
40
|
end
|
41
41
|
|
42
|
-
spec.add_development_dependency 'pry', '~> 0.9.0'
|
43
|
-
spec.add_development_dependency 'yard', '~> 0.8.0'
|
44
|
-
spec.add_development_dependency 'redcarpet', '~> 2.3.0'
|
42
|
+
spec.add_development_dependency 'pry', '~> 0.9', '>= 0.9.0'
|
43
|
+
spec.add_development_dependency 'yard', '~> 0.8', '>= 0.8.0'
|
44
|
+
spec.add_development_dependency 'redcarpet', '~> 2.3', '>= 2.3.0'
|
45
45
|
end
|
data/lib/aviator/core/session.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
module Aviator
|
2
2
|
|
3
|
+
#
|
4
|
+
# Manages a provider (e.g. OpenStack) session.
|
5
|
+
#
|
6
|
+
# Author:: Mark Maglana (mmaglana@gmail.com)
|
7
|
+
# Copyright:: Copyright (c) 2014 Mark Maglana
|
8
|
+
# License:: Distributed under the MIT license
|
9
|
+
# Homepage:: http://aviator.github.io/www/
|
10
|
+
#
|
3
11
|
class Session
|
4
12
|
|
5
13
|
class AuthenticationError < StandardError
|
@@ -42,7 +50,91 @@ module Aviator
|
|
42
50
|
end
|
43
51
|
end
|
44
52
|
|
45
|
-
|
53
|
+
#
|
54
|
+
# Create a new Session instance with options provided in <tt>opts</tt> which can
|
55
|
+
# have many forms discussed below.
|
56
|
+
#
|
57
|
+
# <b>Initialize with a config file</b>
|
58
|
+
#
|
59
|
+
# Aviator::Session.new(:config_file => 'path/to/aviator.yml', :environment => :production)
|
60
|
+
#
|
61
|
+
# In the above example, the config file must have the following form:
|
62
|
+
#
|
63
|
+
# production:
|
64
|
+
# provider: openstack
|
65
|
+
# auth_service:
|
66
|
+
# name: identity
|
67
|
+
# host_uri: 'http://my.openstackenv.org:5000'
|
68
|
+
# request: create_token
|
69
|
+
# validator: list_tenants
|
70
|
+
# api_version: v2
|
71
|
+
# auth_credentials:
|
72
|
+
# username: myusername
|
73
|
+
# password: mypassword
|
74
|
+
# tenant_name: myproject
|
75
|
+
#
|
76
|
+
# Once the session has been instantiated, you may authenticate against the
|
77
|
+
# provider as follows:
|
78
|
+
#
|
79
|
+
# session.authenticate
|
80
|
+
#
|
81
|
+
# Note that the required items under <tt>auth_credentials</tt> in the config
|
82
|
+
# file depends on the required parameters of the request class declared under
|
83
|
+
# <tt>auth_service</tt>. If writing the <tt>auth_credentials</tt> in the config
|
84
|
+
# file is not acceptable, you may omit it and just supply the credentials at
|
85
|
+
# runtime. For instance, assume that the <tt>auth_credentials</tt> section in the
|
86
|
+
# config file above is missing. You would then authenticate as follows:
|
87
|
+
#
|
88
|
+
# session.authenticate do |params|
|
89
|
+
# params.username = ARGV[0]
|
90
|
+
# params.password = ARGV[1]
|
91
|
+
# params.tenant_name = ARGV[2]
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# Please see Session#authenticate for more info.
|
95
|
+
#
|
96
|
+
# Note that while the example config file above only has one environment (production),
|
97
|
+
# you can declare an arbitrary number of environments in your config file. Shifting
|
98
|
+
# between environments is as simple as changing the <tt>:environment</tt> to refer to that.
|
99
|
+
#
|
100
|
+
#
|
101
|
+
# <b>Initialize with an in-memory hash</b>
|
102
|
+
#
|
103
|
+
# You can create an in-memory hash which is similar in structure to the config file except
|
104
|
+
# that you don't need to specify an environment name. For example:
|
105
|
+
#
|
106
|
+
# configuration = {
|
107
|
+
# :provider => 'openstack',
|
108
|
+
# :auth_service => {
|
109
|
+
# :name => 'identity',
|
110
|
+
# :host_uri => 'http://devstack:5000/v2.0',
|
111
|
+
# :request => 'create_token',
|
112
|
+
# :validator => 'list_tenants'
|
113
|
+
# }
|
114
|
+
# }
|
115
|
+
#
|
116
|
+
# Supply this to the initializer using the <tt>:config</tt> option. For example:
|
117
|
+
#
|
118
|
+
# Aviator::Session.new(:config => configuration)
|
119
|
+
#
|
120
|
+
#
|
121
|
+
# <b>Initialize with a session dump</b>
|
122
|
+
#
|
123
|
+
# You can create a new Session instance using a dump from another instance. For example:
|
124
|
+
#
|
125
|
+
# session_dump = session1.dump
|
126
|
+
# session2 = Aviator::Session.new(:session_dump => session_dump)
|
127
|
+
#
|
128
|
+
# However, Session.load is cleaner and recommended over this method.
|
129
|
+
#
|
130
|
+
#
|
131
|
+
# <b>Optionally supply a log file</b>
|
132
|
+
#
|
133
|
+
# In all forms above, you may optionally add a <tt>:log_file</tt> option to make
|
134
|
+
# Aviator write all HTTP calls to the given path. For example:
|
135
|
+
#
|
136
|
+
# Aviator::Session.new(:config_file => 'path/to/aviator.yml', :environment => :production, :log_file => 'path/to/log')
|
137
|
+
#
|
46
138
|
def initialize(opts={})
|
47
139
|
if opts.has_key? :session_dump
|
48
140
|
initialize_with_dump(opts[:session_dump])
|
@@ -57,15 +149,47 @@ module Aviator
|
|
57
149
|
@log_file = opts[:log_file]
|
58
150
|
end
|
59
151
|
|
60
|
-
|
152
|
+
#
|
153
|
+
# Authenticates against the auth_service request class declared in the session's
|
154
|
+
# configuration during initialization. Please see Session.new for more information
|
155
|
+
# on declaring the request class to use for authentication.
|
156
|
+
#
|
157
|
+
# If the auth_service request class accepts a parameter block, you may also supply that
|
158
|
+
# when calling this method and it will be directly passed to the request. For example:
|
159
|
+
#
|
160
|
+
# session = Aviator::Session.new(:config => config)
|
161
|
+
# session.authenticate do |params|
|
162
|
+
# params.username = username
|
163
|
+
# params.password = password
|
164
|
+
# params.tenant_name = project
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# Expects an HTTP status 200 or 201. Any other status is treated as a failure.
|
168
|
+
#
|
169
|
+
# Note that you can also treat the block's argument like a hash with the attribute
|
170
|
+
# names as the keys. For example, we can rewrite the above as:
|
171
|
+
#
|
172
|
+
# session = Aviator::Session.new(:config => config)
|
173
|
+
# session.authenticate do |params|
|
174
|
+
# params[:username] = username
|
175
|
+
# params[:password] = password
|
176
|
+
# params[:tenant_name] = project
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# Keys can be symbols or strings.
|
180
|
+
#
|
61
181
|
def authenticate(&block)
|
62
182
|
block ||= lambda do |params|
|
63
|
-
|
64
|
-
|
183
|
+
config[:auth_credentials].each do |key, value|
|
184
|
+
begin
|
185
|
+
params[key] = value
|
186
|
+
rescue NameError => e
|
187
|
+
raise NameError.new("Unknown param name '#{key}'")
|
188
|
+
end
|
65
189
|
end
|
66
190
|
end
|
67
191
|
|
68
|
-
response = auth_service.request
|
192
|
+
response = auth_service.request config[:auth_service][:request].to_sym, &block
|
69
193
|
|
70
194
|
if [200, 201].include? response.status
|
71
195
|
@auth_response = Hashish.new({
|
@@ -79,20 +203,43 @@ module Aviator
|
|
79
203
|
self
|
80
204
|
end
|
81
205
|
|
82
|
-
|
206
|
+
#
|
207
|
+
# Returns true if the session has been authenticated.
|
208
|
+
#
|
83
209
|
def authenticated?
|
84
210
|
!auth_response.nil?
|
85
211
|
end
|
86
212
|
|
213
|
+
#
|
214
|
+
# Returns its configuration.
|
215
|
+
#
|
216
|
+
def config
|
217
|
+
@config
|
218
|
+
end
|
87
219
|
|
220
|
+
#
|
221
|
+
# Returns a JSON string of its configuration and auth_data. This string can be streamed
|
222
|
+
# or stored and later re-loaded in another Session instance. For example:
|
223
|
+
#
|
224
|
+
# session = Aviator::Session.new(:config => configuration)
|
225
|
+
# str = session.dump
|
226
|
+
#
|
227
|
+
# # time passes...
|
228
|
+
#
|
229
|
+
# session = Aviator::Session.load(str)
|
230
|
+
#
|
88
231
|
def dump
|
89
232
|
JSON.generate({
|
90
|
-
:
|
233
|
+
:config => config,
|
91
234
|
:auth_response => auth_response
|
92
235
|
})
|
93
236
|
end
|
94
237
|
|
95
238
|
|
239
|
+
#
|
240
|
+
# Same as Session::load but re-uses the Session instance this method is
|
241
|
+
# called on instead of creating a new one.
|
242
|
+
#
|
96
243
|
def load(session_dump)
|
97
244
|
initialize_with_dump(session_dump)
|
98
245
|
update_services_session_data
|
@@ -111,6 +258,14 @@ module Aviator
|
|
111
258
|
end
|
112
259
|
|
113
260
|
|
261
|
+
#
|
262
|
+
# Creates a new Session object from a previous session's dump. See Session#dump for
|
263
|
+
# more information.
|
264
|
+
#
|
265
|
+
# If you want the newly deserialized session to log its output, make sure to indicate it on load
|
266
|
+
#
|
267
|
+
# Aviator::Session.load(session_dump_str, :log_file => 'path/to/aviator.log')
|
268
|
+
#
|
114
269
|
def self.load(session_dump, opts={})
|
115
270
|
opts[:session_dump] = session_dump
|
116
271
|
|
@@ -118,13 +273,72 @@ module Aviator
|
|
118
273
|
end
|
119
274
|
|
120
275
|
|
276
|
+
#
|
277
|
+
# Returns the log file path. May be nil if none was provided during initialization.
|
278
|
+
#
|
279
|
+
def log_file
|
280
|
+
@log_file
|
281
|
+
end
|
282
|
+
|
283
|
+
|
284
|
+
#
|
285
|
+
# Calls the given request of the given service. An example call might look like:
|
286
|
+
#
|
287
|
+
# session.request :compute_service, :create_server do |p|
|
288
|
+
# p.name = "My Server"
|
289
|
+
# p.image_ref = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29"
|
290
|
+
# p.flavor_ref = "fa283da1-59a5-4245-8569-b6eadf69f10b"
|
291
|
+
# end
|
292
|
+
#
|
293
|
+
# Note that you can also treat the block's argument like a hash with the attribute
|
294
|
+
# names as the keys. For example, we can rewrite the above as:
|
295
|
+
#
|
296
|
+
# session.request :compute_service, :create_server do |p|
|
297
|
+
# p[:name] = "My Server"
|
298
|
+
# p[:image_ref] = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29"
|
299
|
+
# p[:flavor_ref] = "fa283da1-59a5-4245-8569-b6eadf69f10b"
|
300
|
+
# end
|
301
|
+
#
|
302
|
+
# Keys can be symbols or strings.
|
303
|
+
#
|
304
|
+
# ---
|
305
|
+
#
|
306
|
+
# <b>Request Options</b>
|
307
|
+
#
|
308
|
+
# You can further customize how the request is fulfilled by providing one or more
|
309
|
+
# options to the method call. For example, the following ensures that the request
|
310
|
+
# will call the :create_server request for the v1 API.
|
311
|
+
#
|
312
|
+
# session.request :compute_service, :create_server, :api_version => v1
|
313
|
+
#
|
314
|
+
# The available options vary depending on the provider. See the documentation
|
315
|
+
# on the provider's Provider class for more information (e.g. Aviator::OpenStack::Provider)
|
316
|
+
#
|
317
|
+
def request(service_name, request_name, opts={}, ¶ms)
|
318
|
+
service = send("#{service_name.to_s}_service")
|
319
|
+
service.request(request_name, opts, ¶ms)
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
#
|
324
|
+
# Returns true if the session is still valid in the underlying provider. This method does this
|
325
|
+
# by calling the validator request class declared declared under <tt>auth_service</tt> in the
|
326
|
+
# configuration. The validator can be any request class as long as:
|
327
|
+
#
|
328
|
+
# * The request class exists!
|
329
|
+
# * Does not require any parameters
|
330
|
+
# * It returns an HTTP status 200 or 203 to indicate auth info validity.
|
331
|
+
# * It returns any other HTTP status to indicate that the auth info is invalid.
|
332
|
+
#
|
333
|
+
# See Session::new for an example on how to specify the request class to use for session validation.
|
334
|
+
#
|
121
335
|
def validate
|
122
336
|
raise NotAuthenticatedError.new unless authenticated?
|
123
|
-
raise ValidatorNotDefinedError.new unless
|
337
|
+
raise ValidatorNotDefinedError.new unless config[:auth_service][:validator]
|
124
338
|
|
125
|
-
auth_with_bootstrap = auth_response.merge({ :auth_service =>
|
339
|
+
auth_with_bootstrap = auth_response.merge({ :auth_service => config[:auth_service] })
|
126
340
|
|
127
|
-
response = auth_service.request
|
341
|
+
response = auth_service.request config[:auth_service][:validator].to_sym, :session_data => auth_with_bootstrap
|
128
342
|
response.status == 200 || response.status == 203
|
129
343
|
end
|
130
344
|
|
@@ -139,27 +353,22 @@ module Aviator
|
|
139
353
|
|
140
354
|
def auth_service
|
141
355
|
@auth_service ||= Service.new(
|
142
|
-
:provider =>
|
143
|
-
:service =>
|
144
|
-
:default_session_data => { :auth_service =>
|
356
|
+
:provider => config[:provider],
|
357
|
+
:service => config[:auth_service][:name],
|
358
|
+
:default_session_data => { :auth_service => config[:auth_service] },
|
145
359
|
:log_file => log_file
|
146
360
|
)
|
147
361
|
end
|
148
362
|
|
149
363
|
|
150
|
-
def environment
|
151
|
-
@environment
|
152
|
-
end
|
153
|
-
|
154
|
-
|
155
364
|
def get_service_obj(service_name)
|
156
365
|
@services ||= {}
|
157
366
|
|
158
367
|
if @services[service_name].nil?
|
159
|
-
default_options =
|
368
|
+
default_options = config["#{ service_name }_service"]
|
160
369
|
|
161
370
|
@services[service_name] = Service.new(
|
162
|
-
:provider =>
|
371
|
+
:provider => config[:provider],
|
163
372
|
:service => service_name,
|
164
373
|
:default_session_data => auth_response,
|
165
374
|
:default_options => default_options,
|
@@ -174,28 +383,23 @@ module Aviator
|
|
174
383
|
def initialize_with_config(config_path, environment)
|
175
384
|
raise InvalidConfigFilePathError.new(config_path) unless Pathname.new(config_path).file?
|
176
385
|
|
177
|
-
|
386
|
+
all_config = Hashish.new(YAML.load_file(config_path))
|
178
387
|
|
179
|
-
raise EnvironmentNotDefinedError.new(config_path, environment) unless
|
388
|
+
raise EnvironmentNotDefinedError.new(config_path, environment) unless all_config[environment]
|
180
389
|
|
181
|
-
@
|
390
|
+
@config = all_config[environment]
|
182
391
|
end
|
183
392
|
|
184
393
|
|
185
394
|
def initialize_with_dump(session_dump)
|
186
395
|
session_info = Hashish.new(JSON.parse(session_dump))
|
187
|
-
@
|
396
|
+
@config = session_info[:config]
|
188
397
|
@auth_response = session_info[:auth_response]
|
189
398
|
end
|
190
399
|
|
191
400
|
|
192
401
|
def initialize_with_hash(hash_obj)
|
193
|
-
@
|
194
|
-
end
|
195
|
-
|
196
|
-
|
197
|
-
def log_file
|
198
|
-
@log_file
|
402
|
+
@config = Hashish.new(hash_obj)
|
199
403
|
end
|
200
404
|
|
201
405
|
|
@@ -1,6 +1,68 @@
|
|
1
1
|
module Aviator
|
2
2
|
module Openstack
|
3
3
|
|
4
|
+
#
|
5
|
+
# Manages a provider (e.g. OpenStack) session.
|
6
|
+
#
|
7
|
+
# Author:: Mark Maglana (mmaglana@gmail.com)
|
8
|
+
# Copyright:: Copyright (c) 2014 Mark Maglana
|
9
|
+
# License:: Distributed under the MIT license
|
10
|
+
# Homepage:: http://aviator.github.io/www/
|
11
|
+
#
|
12
|
+
# <b>Request Options</b>
|
13
|
+
#
|
14
|
+
# The following options may be used in combination with each other when calling
|
15
|
+
# an OpenStack request class
|
16
|
+
#
|
17
|
+
# :api_version => :v2::
|
18
|
+
# Forces Aviator to use the request class for the v2 API. For any other
|
19
|
+
# version, replace Note that this may throw an error if no such request
|
20
|
+
# class exists. If you want to globally specify the API version to use for
|
21
|
+
# a specific service, declare it in your config file under the correct
|
22
|
+
# environment. For example:
|
23
|
+
#
|
24
|
+
# production:
|
25
|
+
# provider: openstack
|
26
|
+
# ...
|
27
|
+
# compute_service:
|
28
|
+
# api_version: v2
|
29
|
+
#
|
30
|
+
# Note that the <tt>:api_version</tt> option overrides whatever is declared in the
|
31
|
+
# configuration.
|
32
|
+
#
|
33
|
+
# :endpoint_type => (:public|:admin)::
|
34
|
+
# This allows you to be specific about the endpoint type in cases where two
|
35
|
+
# request classes under admin and public endpoints of the same service share
|
36
|
+
# the same name. This is true, for example, for the :list_tenants request of
|
37
|
+
# the identity service's v2 API. Its public endpoint will return only the tenants
|
38
|
+
# the user is a member of whereas the admin endpoint will return all tenants
|
39
|
+
# in the system.
|
40
|
+
#
|
41
|
+
# :session_data => Hash::
|
42
|
+
# Under normal situations, you wouldn't need to use this as it is automatically populated
|
43
|
+
# by the Session object provided it is authenticated. The specific use case when you'd
|
44
|
+
# need to set thsi optin is when you want to use Aviator to seed your OpenStack installation.
|
45
|
+
# In such a scenario, you would need to use a service token since no usernames and tenants
|
46
|
+
# would exist yet in the environment. To use a service token with Aviator, you will need to
|
47
|
+
# write something similar to the following example:
|
48
|
+
#
|
49
|
+
# openstack = Aviator::Session.new(:config => { :provider => 'openstack'})
|
50
|
+
#
|
51
|
+
# session_data = {:base_url => 'http://example.com',
|
52
|
+
# :service_token => 'service-token-created-at-openstack-install-time'}
|
53
|
+
#
|
54
|
+
# openstack.request :identity, :create_tenant, :api_version => :v2, :session_data => session_data) do |params|
|
55
|
+
# params.name = 'Tenant A'
|
56
|
+
# params.description = 'First Tenant!'
|
57
|
+
# params.enabled = true
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# Notice how the above code skips authentication. This is because the service token is
|
61
|
+
# pre-validated and ready for use with any request. Also note how we're providing a <tt>:base_url</tt>
|
62
|
+
# member in our session data. This is necessary since we normally get the service endpoints from
|
63
|
+
# Keystone when we authenticate. Now since we are not authenticating against Keystone, we don't have
|
64
|
+
# that catalogue to begin with. Thus the need to hardcode it in the request.
|
65
|
+
#
|
4
66
|
module Provider
|
5
67
|
|
6
68
|
class MultipleServiceApisError < StandardError
|
@@ -35,6 +97,7 @@ EOF
|
|
35
97
|
|
36
98
|
class << self
|
37
99
|
|
100
|
+
#:nodoc:
|
38
101
|
def find_request(service, name, session_data, options)
|
39
102
|
service = service.to_s
|
40
103
|
endpoint_type = options[:endpoint_type]
|