fog-openstack 0.1.31 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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