fog-openstack 0.1.31 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +4 -1
  4. data/.travis.yml +5 -5
  5. data/.zuul.yaml +8 -8
  6. data/Rakefile +14 -4
  7. data/fog-openstack.gemspec +3 -2
  8. data/lib/fog/baremetal/openstack.rb +6 -24
  9. data/lib/fog/compute/openstack.rb +6 -27
  10. data/lib/fog/compute/openstack/requests/create_security_group.rb +1 -1
  11. data/lib/fog/compute/openstack/requests/create_server.rb +1 -1
  12. data/lib/fog/compute/openstack/requests/evacuate_server.rb +1 -5
  13. data/lib/fog/container_infra/openstack.rb +6 -25
  14. data/lib/fog/dns/openstack/v1.rb +5 -17
  15. data/lib/fog/dns/openstack/v2.rb +5 -22
  16. data/lib/fog/event/openstack.rb +5 -24
  17. data/lib/fog/identity/openstack.rb +24 -71
  18. data/lib/fog/identity/openstack/v2.rb +6 -4
  19. data/lib/fog/identity/openstack/v3.rb +5 -11
  20. data/lib/fog/image/openstack/v1.rb +8 -21
  21. data/lib/fog/image/openstack/v2.rb +8 -21
  22. data/lib/fog/image/openstack/v2/models/image.rb +1 -1
  23. data/lib/fog/introspection/openstack.rb +4 -19
  24. data/lib/fog/key_manager/openstack.rb +5 -47
  25. data/lib/fog/metering/openstack.rb +8 -23
  26. data/lib/fog/metric/openstack.rb +7 -26
  27. data/lib/fog/monitoring/openstack.rb +3 -12
  28. data/lib/fog/network/openstack.rb +5 -26
  29. data/lib/fog/network/openstack/requests/set_tenant.rb +0 -1
  30. data/lib/fog/nfv/openstack.rb +4 -24
  31. data/lib/fog/openstack.rb +17 -431
  32. data/lib/fog/openstack/auth/catalog.rb +64 -0
  33. data/lib/fog/openstack/auth/catalog/v2.rb +23 -0
  34. data/lib/fog/openstack/auth/catalog/v3.rb +23 -0
  35. data/lib/fog/openstack/auth/name.rb +65 -0
  36. data/lib/fog/openstack/auth/token.rb +69 -0
  37. data/lib/fog/openstack/auth/token/v2.rb +70 -0
  38. data/lib/fog/openstack/auth/token/v3.rb +116 -0
  39. data/lib/fog/openstack/core.rb +100 -76
  40. data/lib/fog/openstack/version.rb +1 -1
  41. data/lib/fog/orchestration/openstack.rb +4 -21
  42. data/lib/fog/planning/openstack.rb +13 -23
  43. data/lib/fog/shared_file_system/openstack.rb +10 -27
  44. data/lib/fog/storage/openstack.rb +6 -11
  45. data/lib/fog/volume/openstack.rb +1 -1
  46. data/lib/fog/volume/openstack/models/backup.rb +2 -2
  47. data/lib/fog/volume/openstack/requests/restore_backup.rb +2 -2
  48. data/lib/fog/volume/openstack/requests/update_volume.rb +12 -1
  49. data/lib/fog/volume/openstack/v1.rb +4 -21
  50. data/lib/fog/volume/openstack/v1/models/volume.rb +1 -2
  51. data/lib/fog/volume/openstack/v1/requests/update_volume.rb +0 -17
  52. data/lib/fog/volume/openstack/v2.rb +4 -21
  53. data/lib/fog/volume/openstack/v2/models/volume.rb +1 -1
  54. data/lib/fog/volume/openstack/v2/requests/update_volume.rb +0 -18
  55. data/lib/fog/workflow/openstack/v2.rb +5 -22
  56. data/playbooks/fog-openstack-unittest-spec/run.yaml +2 -1
  57. data/playbooks/fog-openstack-unittest-test/run.yaml +2 -1
  58. data/unit/auth/catalog_test.rb +252 -0
  59. data/unit/auth/name_test.rb +115 -0
  60. data/unit/auth/token_test.rb +478 -0
  61. data/unit/auth_helper.rb +102 -0
  62. data/unit/test_helper.rb +6 -0
  63. metadata +41 -16
  64. data/lib/fog/compute/openstack/requests/list_tenants.rb +0 -43
@@ -12,7 +12,7 @@ module Fog
12
12
  :openstack_project_name, :openstack_project_id,
13
13
  :openstack_project_domain, :openstack_user_domain, :openstack_domain_name,
14
14
  :openstack_project_domain_id, :openstack_user_domain_id, :openstack_domain_id,
15
- :openstack_identity_prefix, :openstack_temp_url_key, :openstack_cache_ttl
15
+ :openstack_identity_api_version, :openstack_temp_url_key, :openstack_cache_ttl
16
16
 
17
17
  model_path 'fog/monitoring/openstack/models'
18
18
  model :metric
@@ -78,17 +78,8 @@ module Fog
78
78
  Fog::Monitoring::OpenStack::NotFound
79
79
  end
80
80
 
81
- def initialize(options = {})
82
- initialize_identity options
83
-
84
- @openstack_service_type = options[:openstack_service_type] || ['monitoring']
85
- @openstack_service_name = options[:openstack_service_name]
86
-
87
- @connection_options = options[:connection_options] || {}
88
-
89
- authenticate
90
- @persistent = options[:persistent] || false
91
- @connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
81
+ def default_service_type
82
+ %w[monitoring]
92
83
  end
93
84
  end
94
85
  end
@@ -3,8 +3,6 @@
3
3
  module Fog
4
4
  module Network
5
5
  class OpenStack < Fog::Service
6
- SUPPORTED_VERSIONS = /v2(\.0)*/
7
-
8
6
  requires :openstack_auth_url
9
7
  recognizes :openstack_auth_token, :openstack_management_url,
10
8
  :persistent, :openstack_service_type, :openstack_service_name,
@@ -15,7 +13,7 @@ module Fog
15
13
  :openstack_project_name, :openstack_project_id,
16
14
  :openstack_project_domain, :openstack_user_domain, :openstack_domain_name,
17
15
  :openstack_project_domain_id, :openstack_user_domain_id, :openstack_domain_id,
18
- :openstack_identity_prefix
16
+ :openstack_identity_api_version
19
17
 
20
18
  ## MODELS
21
19
  #
@@ -429,8 +427,6 @@ module Fog
429
427
  def initialize(options = {})
430
428
  @auth_token = Fog::Mock.random_base64(64)
431
429
  @auth_token_expiration = (Time.now.utc + 86400).iso8601
432
-
433
- initialize_identity options
434
430
  end
435
431
 
436
432
  def data
@@ -449,29 +445,12 @@ module Fog
449
445
  Fog::Network::OpenStack::NotFound
450
446
  end
451
447
 
452
- def initialize(options = {})
453
- initialize_identity options
454
-
455
- @openstack_service_type = options[:openstack_service_type] || ['network']
456
- @openstack_service_name = options[:openstack_service_name]
457
-
458
- @connection_options = options[:connection_options] || {}
459
-
460
- authenticate
461
- set_api_path
462
-
463
- @persistent = options[:persistent] || false
464
- @connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
448
+ def default_path_prefix
449
+ 'v2.0'
465
450
  end
466
451
 
467
- def set_api_path
468
- @path.sub!(%r{/$}, '')
469
- unless @path.match(SUPPORTED_VERSIONS)
470
- @path = Fog::OpenStack.get_supported_version_path(SUPPORTED_VERSIONS,
471
- @openstack_management_uri,
472
- @auth_token,
473
- @connection_options)
474
- end
452
+ def default_service_type
453
+ %w[network]
475
454
  end
476
455
  end
477
456
  end
@@ -6,7 +6,6 @@ module Fog
6
6
  @openstack_must_reauthenticate = true
7
7
  @openstack_tenant = tenant.to_s
8
8
  authenticate
9
- set_api_path
10
9
  end
11
10
  end
12
11
 
@@ -82,8 +82,6 @@ module Fog
82
82
  def initialize(options = {})
83
83
  @auth_token = Fog::Mock.random_base64(64)
84
84
  @auth_token_expiration = (Time.now.utc + 86_400).iso8601
85
-
86
- initialize_identity options
87
85
  end
88
86
 
89
87
  def data
@@ -102,30 +100,12 @@ module Fog
102
100
  Fog::NFV::OpenStack::NotFound
103
101
  end
104
102
 
105
- def initialize(options = {})
106
- initialize_identity options
107
-
108
- @openstack_service_type = options[:openstack_service_type] || ['servicevm']
109
- @openstack_service_name = options[:openstack_service_name]
110
-
111
- @connection_options = options[:connection_options] || {}
112
-
113
- authenticate
114
- set_api_path
115
-
116
- @persistent = options[:persistent] || false
117
- @connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
103
+ def default_path_prefix
104
+ 'v1.0'
118
105
  end
119
106
 
120
- def set_api_path
121
- unless @path.match(SUPPORTED_VERSIONS)
122
- @path = "/" + Fog::OpenStack.get_supported_version(
123
- SUPPORTED_VERSIONS,
124
- @openstack_management_uri,
125
- @auth_token,
126
- @connection_options
127
- )
128
- end
107
+ def default_service_type
108
+ %w[servicevm]
129
109
  end
130
110
  end
131
111
  end
data/lib/fog/openstack.rb CHANGED
@@ -84,6 +84,8 @@ module Fog
84
84
  end
85
85
 
86
86
  module OpenStack
87
+ require 'fog/openstack/auth/token'
88
+
87
89
  autoload :VERSION, 'fog/openstack/version'
88
90
 
89
91
  autoload :Core, 'fog/openstack/core'
@@ -123,425 +125,10 @@ module Fog
123
125
  Fog::OpenStack.token_cache = {}
124
126
  end
125
127
 
126
- def self.authenticate(options, connection_options = {})
127
- case options[:openstack_auth_uri].path
128
- when /v1(\.\d+)?/
129
- authenticate_v1(options, connection_options)
130
- when /v2(\.\d+)?/
131
- authenticate_v2(options, connection_options)
132
- when /v3(\.\d+)?/
133
- authenticate_v3(options, connection_options)
134
- else
135
- authenticate_v2(options, connection_options)
136
- end
137
- end
138
-
139
- # legacy v1.0 style auth
140
- def self.authenticate_v1(options, connection_options = {})
141
- uri = options[:openstack_auth_uri]
142
- connection = Fog::Core::Connection.new(uri.to_s, false, connection_options)
143
- @openstack_api_key = options[:openstack_api_key]
144
- @openstack_username = options[:openstack_username]
145
-
146
- response = connection.request({
147
- :expects => [200, 204],
148
- :headers => {
149
- 'X-Auth-Key' => @openstack_api_key,
150
- 'X-Auth-User' => @openstack_username
151
- },
152
- :method => 'GET',
153
- :path => (uri.path and not uri.path.empty?) ? uri.path : 'v1.0'
154
- })
155
-
156
- return {
157
- :token => response.headers['X-Auth-Token'],
158
- :server_management_url => response.headers['X-Server-Management-Url'] || response.headers['X-Storage-Url'],
159
- :identity_public_endpoint => response.headers['X-Keystone']
160
- }
161
- end
162
-
163
- # Keystone Style Auth
164
- def self.authenticate_v2(options, connection_options = {})
165
- uri = options[:openstack_auth_uri]
166
- tenant_name = options[:openstack_tenant]
167
- service_type = options[:openstack_service_type]
168
- service_name = options[:openstack_service_name]
169
- identity_service_type = options[:openstack_identity_service_type]
170
- endpoint_type = (options[:openstack_endpoint_type] || 'publicURL').to_s
171
- openstack_region = options[:openstack_region]
172
-
173
- body = retrieve_tokens_v2(options, connection_options)
174
- service = get_service(body, service_type, service_name)
175
-
176
- options[:unscoped_token] = body['access']['token']['id']
177
-
178
- unless service
179
- unless tenant_name
180
- response = Fog::Core::Connection.new(
181
- "#{uri.scheme}://#{uri.host}:#{uri.port}/v2.0/tenants", false, connection_options).request({
182
- :expects => [200, 204],
183
- :headers => {'Content-Type' => 'application/json',
184
- 'Accept' => 'application/json',
185
- 'X-Auth-Token' => body['access']['token']['id']},
186
- :method => 'GET'
187
- })
188
-
189
- body = Fog::JSON.decode(response.body)
190
- if body['tenants'].empty?
191
- raise Fog::Errors::NotFound.new('No Tenant Found')
192
- else
193
- options[:openstack_tenant] = body['tenants'].first['name']
194
- end
195
- end
196
-
197
- body = retrieve_tokens_v2(options, connection_options)
198
- service = get_service(body, service_type, service_name)
199
-
200
- end
201
-
202
- unless service
203
- available = body['access']['serviceCatalog'].map { |endpoint|
204
- endpoint['type']
205
- }.sort.join ', '
206
-
207
- missing = service_type.join ', '
208
-
209
- message = "Could not find service #{missing}. Have #{available}"
210
-
211
- raise Fog::Errors::NotFound, message
212
- end
213
-
214
- service['endpoints'] = service['endpoints'].select do |endpoint|
215
- endpoint['region'] == openstack_region
216
- end if openstack_region
217
-
218
- if service['endpoints'].empty?
219
- raise Fog::Errors::NotFound.new("No endpoints available for region '#{openstack_region}'")
220
- end if openstack_region
221
-
222
- regions = service["endpoints"].map{ |e| e['region'] }.uniq
223
- if regions.count > 1
224
- raise Fog::Errors::NotFound.new("Multiple regions available choose one of these '#{regions.join(',')}'")
225
- end
226
-
227
- identity_service = get_service(body, identity_service_type) if identity_service_type
228
- tenant = body['access']['token']['tenant']
229
- user = body['access']['user']
230
-
231
- management_url = service['endpoints'].find{|s| s[endpoint_type]}[endpoint_type]
232
- identity_url = identity_service['endpoints'].find{|s| s['publicURL']}['publicURL'] if identity_service
233
-
234
- {
235
- :user => user,
236
- :tenant => tenant,
237
- :identity_public_endpoint => identity_url,
238
- :server_management_url => management_url,
239
- :token => body['access']['token']['id'],
240
- :expires => body['access']['token']['expires'],
241
- :current_user_id => body['access']['user']['id'],
242
- :unscoped_token => options[:unscoped_token]
243
- }
244
- end
245
-
246
- # Keystone Style Auth
247
- def self.authenticate_v3(options, connection_options = {})
248
- uri = options[:openstack_auth_uri]
249
- project_name = options[:openstack_project_name]
250
- service_type = options[:openstack_service_type]
251
- service_name = options[:openstack_service_name]
252
- identity_service_type = options[:openstack_identity_service_type]
253
- endpoint_type = map_endpoint_type(options[:openstack_endpoint_type] || 'publicURL')
254
- openstack_region = options[:openstack_region]
255
-
256
- token, body = retrieve_tokens_v3 options, connection_options
257
-
258
- service = get_service_v3(body, service_type, service_name, openstack_region, options)
259
-
260
- options[:unscoped_token] = token
261
-
262
- unless service
263
- unless project_name
264
- request_body = {
265
- :expects => [200],
266
- :headers => {'Content-Type' => 'application/json',
267
- 'Accept' => 'application/json',
268
- 'X-Auth-Token' => token},
269
- :method => 'GET'
270
- }
271
- user_id = body['token']['user']['id']
272
- project_uri = uri.clone
273
- project_uri.path = uri.path.sub('/auth/tokens', "/users/#{user_id}/projects")
274
- project_uri_param = "#{project_uri.scheme}://#{project_uri.host}:#{project_uri.port}#{project_uri.path}"
275
- response = Fog::Core::Connection.new(project_uri_param, false, connection_options).request(request_body)
276
-
277
- projects_body = Fog::JSON.decode(response.body)
278
- if projects_body['projects'].empty?
279
- options[:openstack_domain_id] = body['token']['user']['domain']['id']
280
- else
281
- options[:openstack_project_id] = projects_body['projects'].first['id']
282
- options[:openstack_project_name] = projects_body['projects'].first['name']
283
- options[:openstack_domain_id] = projects_body['projects'].first['domain_id']
284
- end
285
- end
286
-
287
- token, body = retrieve_tokens_v3(options, connection_options)
288
- service = get_service_v3(body, service_type, service_name, openstack_region, options)
289
- end
290
-
291
- # If no identity endpoint is found, try the auth uri (slicing /auth/tokens)
292
- # It covers the case where identityv3 endpoint is not present in the catalog but we have to use it
293
- unless service
294
- if service_type.include? "identity"
295
- identity_uri = uri.to_s.sub('/auth/tokens', '')
296
- response = Fog::Core::Connection.new(identity_uri, false, connection_options).request({:method => 'GET'})
297
- if response.status == 200
298
- service = {
299
- "endpoints" => [{
300
- "url" => identity_uri,
301
- "region" => openstack_region,
302
- "interface" => endpoint_type
303
- }],
304
- "type" => service_type,
305
- "name" => service_name
306
- }
307
- end
308
- end
309
- end
310
-
311
- unless service
312
- available_services = body['token']['catalog'].map { |service|
313
- service['type']
314
- }.sort.join ', '
315
-
316
- available_regions = body['token']['catalog'].map { |service|
317
- service['endpoints'].map { |endpoint|
318
- endpoint['region']
319
- }.uniq
320
- }.uniq.sort.join ', '
321
-
322
- missing = service_type.join ', '
323
-
324
- message = "Could not find service #{missing}#{(' in region '+openstack_region) if openstack_region}."+
325
- " Have #{available_services}#{(' in regions '+available_regions) if openstack_region}"
326
-
327
- raise Fog::Errors::NotFound, message
328
- end
329
-
330
- service['endpoints'] = service['endpoints'].select do |endpoint|
331
- endpoint['region'] == openstack_region && endpoint['interface'] == endpoint_type
332
- end if openstack_region
333
-
334
- if service['endpoints'].empty?
335
- raise Fog::Errors::NotFound.new("No endpoints available for region '#{openstack_region}'")
336
- end if openstack_region
337
-
338
- regions = service["endpoints"].map { |e| e['region'] }.uniq
339
- if regions.count > 1
340
- raise Fog::Errors::NotFound.new("Multiple regions available choose one of these '#{regions.join(',')}'")
341
- end
342
-
343
- identity_service = get_service_v3(body, identity_service_type, nil, nil, :openstack_endpoint_path_matches => /\/v3/) if identity_service_type
344
-
345
- management_url = service['endpoints'].find { |e| e['interface']==endpoint_type }['url']
346
- identity_url = identity_service['endpoints'].find { |e| e['interface']=='public' }['url'] if identity_service
347
-
348
- if body['token']['project']
349
- tenant = body['token']['project']
350
- elsif body['token']['user']['project']
351
- tenant = body['token']['user']['project']
352
- end
353
-
354
- return {
355
- :user => body['token']['user']['name'],
356
- :tenant => tenant,
357
- :identity_public_endpoint => identity_url,
358
- :server_management_url => management_url,
359
- :token => token,
360
- :expires => body['token']['expires_at'],
361
- :current_user_id => body['token']['user']['id'],
362
- :unscoped_token => options[:unscoped_token]
363
- }
364
- end
365
-
366
- def self.get_service(body, service_type=[], service_name=nil)
367
- if not body['access'].nil?
368
- body['access']['serviceCatalog'].find do |s|
369
- if service_name.nil? or service_name.empty?
370
- service_type.include?(s['type'])
371
- else
372
- service_type.include?(s['type']) and s['name'] == service_name
373
- end
374
- end
375
- elsif not body['token']['catalog'].nil?
376
- body['token']['catalog'].find do |s|
377
- if service_name.nil? or service_name.empty?
378
- service_type.include?(s['type'])
379
- else
380
- service_type.include?(s['type']) and s['name'] == service_name
381
- end
382
- end
383
-
384
- end
385
- end
386
-
387
- def self.retrieve_tokens_v2(options, connection_options = {})
388
- api_key = options[:openstack_api_key].to_s
389
- username = options[:openstack_username].to_s
390
- tenant_name = options[:openstack_tenant].to_s
391
- auth_token = options[:openstack_auth_token] || options[:unscoped_token]
392
- uri = options[:openstack_auth_uri]
393
- omit_default_port = options[:openstack_auth_omit_default_port]
394
-
395
- identity_v2_connection = Fog::Core::Connection.new(uri.to_s, false, connection_options)
396
- request_body = {:auth => Hash.new}
397
-
398
- if auth_token
399
- request_body[:auth][:token] = {
400
- :id => auth_token
401
- }
402
- else
403
- request_body[:auth][:passwordCredentials] = {
404
- :username => username,
405
- :password => api_key
406
- }
407
- end
408
- request_body[:auth][:tenantName] = tenant_name if tenant_name
409
-
410
- request = {
411
- :expects => [200, 204],
412
- :headers => {'Content-Type' => 'application/json'},
413
- :body => Fog::JSON.encode(request_body),
414
- :method => 'POST',
415
- :path => (uri.path and not uri.path.empty?) ? uri.path : 'v2.0'
416
- }
417
- request[:omit_default_port] = omit_default_port unless omit_default_port.nil?
418
-
419
- response = identity_v2_connection.request(request)
420
-
421
- Fog::JSON.decode(response.body)
422
- end
423
-
424
- def self.retrieve_tokens_v3(options, connection_options = {})
425
-
426
- api_key = options[:openstack_api_key].to_s
427
- username = options[:openstack_username].to_s
428
- userid = options[:openstack_userid]
429
- domain_id = options[:openstack_domain_id]
430
- domain_name = options[:openstack_domain_name]
431
- project_domain = options[:openstack_project_domain]
432
- project_domain_id = options[:openstack_project_domain_id]
433
- user_domain = options[:openstack_user_domain]
434
- user_domain_id = options[:openstack_user_domain_id]
435
- project_name = options[:openstack_project_name]
436
- project_id = options[:openstack_project_id]
437
- auth_token = options[:openstack_auth_token] || options[:unscoped_token]
438
- uri = options[:openstack_auth_uri]
439
- omit_default_port = options[:openstack_auth_omit_default_port]
440
- cache_ttl = options[:openstack_cache_ttl] || 0
441
-
442
- connection = Fog::Core::Connection.new(uri.to_s, false, connection_options)
443
- request_body = {:auth => {}}
444
-
445
- scope = {}
446
-
447
- if project_name || project_id
448
- scope[:project] = if project_id.nil? then
449
- if project_domain || project_domain_id
450
- {:name => project_name, :domain => project_domain_id.nil? ? {:name => project_domain} : {:id => project_domain_id}}
451
- else
452
- {:name => project_name, :domain => domain_id.nil? ? {:name => domain_name} : {:id => domain_id}}
453
- end
454
- else
455
- {:id => project_id}
456
- end
457
- elsif domain_name || domain_id
458
- scope[:domain] = domain_id.nil? ? {:name => domain_name} : {:id => domain_id}
459
- else
460
- # unscoped token
461
- end
462
-
463
- if auth_token
464
- request_body[:auth][:identity] = {
465
- :methods => %w{token},
466
- :token => {
467
- :id => auth_token
468
- }
469
- }
470
- else
471
- request_body[:auth][:identity] = {
472
- :methods => %w{password},
473
- :password => {
474
- :user => {
475
- :password => api_key
476
- }
477
- }
478
- }
479
-
480
- if userid
481
- request_body[:auth][:identity][:password][:user][:id] = userid
482
- else
483
- if user_domain || user_domain_id
484
- request_body[:auth][:identity][:password][:user].merge! :domain => user_domain_id.nil? ? {:name => user_domain} : {:id => user_domain_id}
485
- elsif domain_name || domain_id
486
- request_body[:auth][:identity][:password][:user].merge! :domain => domain_id.nil? ? {:name => domain_name} : {:id => domain_id}
487
- end
488
- request_body[:auth][:identity][:password][:user][:name] = username
489
- end
490
-
491
- end
492
- request_body[:auth][:scope] = scope unless scope.empty?
493
-
494
- path = (uri.path and not uri.path.empty?) ? uri.path : 'v3'
495
-
496
- response, expires = Fog::OpenStack.token_cache[{:body => request_body, :path => path}] if cache_ttl > 0
497
-
498
- unless response && expires > Time.now
499
- request = {
500
- :expects => [201],
501
- :headers => {'Content-Type' => 'application/json'},
502
- :body => Fog::JSON.encode(request_body),
503
- :method => 'POST',
504
- :path => path
505
- }
506
- request[:omit_default_port] = omit_default_port unless omit_default_port.nil?
507
-
508
- response = connection.request(request)
509
- if cache_ttl > 0
510
- cache = Fog::OpenStack.token_cache
511
- cache[{:body => request_body, :path => path}] = response, Time.now + cache_ttl
512
- Fog::OpenStack.token_cache = cache
513
- end
514
- end
515
-
516
- [response.headers["X-Subject-Token"], Fog::JSON.decode(response.body)]
517
- end
518
-
519
- def self.get_service_v3(hash, service_type=[], service_name=nil, region=nil, options={})
520
-
521
- # Find all services matching any of the types in service_type, filtered by service_name if it's non-nil
522
- services = hash['token']['catalog'].find_all do |s|
523
- if service_name.nil? or service_name.empty?
524
- service_type.include?(s['type'])
525
- else
526
- service_type.include?(s['type']) and s['name'] == service_name
527
- end
528
- end if hash['token']['catalog']
529
-
530
- # Filter the found services by region (if specified) and whether the endpoint path matches the given regex (e.g. /\/v3/)
531
- services.find do |s|
532
- s['endpoints'].any? { |ep| endpoint_region?(ep, region) && endpoint_path_match?(ep, options[:openstack_endpoint_path_matches])}
533
- end if services
534
-
535
- end
536
-
537
128
  def self.endpoint_region?(endpoint, region)
538
129
  region.nil? || endpoint['region'] == region
539
130
  end
540
131
 
541
- def self.endpoint_path_match?(endpoint, match_regex)
542
- match_regex.nil? || URI(endpoint['url']).path =~ match_regex
543
- end
544
-
545
132
  def self.get_supported_version(supported_versions, uri, auth_token, connection_options = {})
546
133
  supported_version = get_version(supported_versions, uri, auth_token, connection_options)
547
134
  version = supported_version['id'] if supported_version
@@ -571,22 +158,14 @@ module Fog
571
158
  end
572
159
  end
573
160
 
574
- def self.map_endpoint_type type
575
- case type
576
- when "publicURL"
577
- "public"
578
- when "internalURL"
579
- "internal"
580
- when "adminURL"
581
- "admin"
582
- end
583
-
584
- end
585
-
586
161
  def self.get_version(supported_versions, uri, auth_token, connection_options = {})
587
162
  version_cache = "#{uri}#{supported_versions}"
588
163
  return @version[version_cache] if @version && @version[version_cache]
589
- connection = Fog::Core::Connection.new("#{uri.scheme}://#{uri.host}:#{uri.port}", false, connection_options)
164
+
165
+ # To allow version discovery we need a "version less" endpoint
166
+ path = uri.path.gsub(/\/v([1-9]+\d*)(\.[1-9]+\d*)*.*$/, '/')
167
+ url = "#{uri.scheme}://#{uri.host}:#{uri.port}#{path}"
168
+ connection = Fog::Core::Connection.new(url, false, connection_options)
590
169
  response = connection.request(
591
170
  :expects => [200, 204, 300],
592
171
  :headers => {'Content-Type' => 'application/json',
@@ -602,10 +181,17 @@ module Fog
602
181
  end
603
182
 
604
183
  def self.extract_version_from_body(body, supported_versions)
605
- return nil if body['versions'].empty?
606
- versions = body['versions'].kind_of?(Array) ? body['versions'] : body['versions']['values']
184
+ versions = []
185
+ unless body['versions'].nil? || body['versions'].empty?
186
+ versions = body['versions'].kind_of?(Array) ? body['versions'] : body['versions']['values']
187
+ end
188
+ # Some version API would return single endpoint rather than endpoints list, try to get it via 'version'.
189
+ unless body['version'].nil? or versions.length != 0
190
+ versions = [body['version']]
191
+ end
607
192
  version = nil
608
- # order is important, preffered status should be first
193
+
194
+ # order is important, preferred status should be first
609
195
  %w(CURRENT stable SUPPORTED DEPRECATED).each do |status|
610
196
  version = versions.find { |x| x['id'].match(supported_versions) && (x['status'] == status) }
611
197
  break if version