fog 1.28.0 → 1.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -0
  3. data/CONTRIBUTING.md +255 -1
  4. data/Rakefile +1 -1
  5. data/fog.gemspec +41 -44
  6. data/lib/fog.rb +1 -0
  7. data/lib/fog/bin.rb +1 -0
  8. data/lib/fog/bin/openstack.rb +2 -0
  9. data/lib/fog/cloudsigma/mock_data.rb +37 -33
  10. data/lib/fog/dnsmadeeasy/models/dns/record.rb +1 -1
  11. data/lib/fog/fogdocker/requests/compute/api_version.rb +1 -1
  12. data/lib/fog/glesys/compute.rb +9 -1
  13. data/lib/fog/glesys/models/compute/server.rb +32 -21
  14. data/lib/fog/glesys/models/compute/ssh_key.rb +28 -0
  15. data/lib/fog/glesys/models/compute/ssh_keys.rb +21 -0
  16. data/lib/fog/glesys/requests/compute/edit.rb +11 -0
  17. data/lib/fog/glesys/requests/compute/ssh_key_add.rb +11 -0
  18. data/lib/fog/glesys/requests/compute/ssh_key_list.rb +11 -0
  19. data/lib/fog/glesys/requests/compute/ssh_key_remove.rb +11 -0
  20. data/lib/fog/google/compute.rb +2 -0
  21. data/lib/fog/google/models/compute/server.rb +14 -0
  22. data/lib/fog/google/requests/compute/start_server.rb +24 -0
  23. data/lib/fog/google/requests/compute/stop_server.rb +24 -0
  24. data/lib/fog/linode/compute.rb +7 -0
  25. data/lib/fog/linode/requests/compute/image_delete.rb +42 -0
  26. data/lib/fog/linode/requests/compute/image_list.rb +64 -0
  27. data/lib/fog/linode/requests/compute/linode_disk_createfromimage.rb +37 -0
  28. data/lib/fog/linode/requests/compute/linode_disk_duplicate.rb +33 -0
  29. data/lib/fog/linode/requests/compute/linode_disk_imagize.rb +37 -0
  30. data/lib/fog/linode/requests/compute/linode_disk_resize.rb +36 -0
  31. data/lib/fog/linode/requests/compute/linode_disk_update.rb +34 -0
  32. data/lib/fog/openstack.rb +1 -0
  33. data/lib/fog/openstack/compute.rb +12 -1
  34. data/lib/fog/openstack/core.rb +159 -5
  35. data/lib/fog/openstack/docs/planning.md +270 -0
  36. data/lib/fog/openstack/examples/planning/basics.rb +53 -0
  37. data/lib/fog/openstack/models/planning/plan.rb +81 -0
  38. data/lib/fog/openstack/models/planning/plans.rb +31 -0
  39. data/lib/fog/openstack/models/planning/role.rb +29 -0
  40. data/lib/fog/openstack/models/planning/roles.rb +16 -0
  41. data/lib/fog/openstack/planning.rb +235 -0
  42. data/lib/fog/openstack/requests/compute/get_hypervisor_statistics.rb +39 -0
  43. data/lib/fog/openstack/requests/identity/check_token.rb +4 -2
  44. data/lib/fog/openstack/requests/identity/validate_token.rb +4 -2
  45. data/lib/fog/openstack/requests/planning/add_role_to_plan.rb +40 -0
  46. data/lib/fog/openstack/requests/planning/create_plan.rb +33 -0
  47. data/lib/fog/openstack/requests/planning/delete_plan.rb +23 -0
  48. data/lib/fog/openstack/requests/planning/get_plan.rb +58 -0
  49. data/lib/fog/openstack/requests/planning/get_plan_templates.rb +28 -0
  50. data/lib/fog/openstack/requests/planning/list_plans.rb +60 -0
  51. data/lib/fog/openstack/requests/planning/list_roles.rb +38 -0
  52. data/lib/fog/openstack/requests/planning/patch_plan.rb +51 -0
  53. data/lib/fog/openstack/requests/planning/remove_role_from_plan.rb +32 -0
  54. data/lib/fog/ovirt/compute.rb +10 -0
  55. data/lib/fog/ovirt/models/compute/affinity_group.rb +25 -0
  56. data/lib/fog/ovirt/models/compute/affinity_groups.rb +20 -0
  57. data/lib/fog/ovirt/models/compute/server.rb +12 -0
  58. data/lib/fog/ovirt/models/compute/volume.rb +2 -0
  59. data/lib/fog/ovirt/requests/compute/add_to_affinity_group.rb +21 -0
  60. data/lib/fog/ovirt/requests/compute/create_affinity_group.rb +18 -0
  61. data/lib/fog/ovirt/requests/compute/destroy_affinity_group.rb +19 -0
  62. data/lib/fog/ovirt/requests/compute/get_affinity_group.rb +18 -0
  63. data/lib/fog/ovirt/requests/compute/list_affinity_group_vms.rb +22 -0
  64. data/lib/fog/ovirt/requests/compute/list_affinity_groups.rb +20 -0
  65. data/lib/fog/ovirt/requests/compute/mock_files/affinitygroup.xml +8 -0
  66. data/lib/fog/ovirt/requests/compute/mock_files/affinitygroup_vms.xml +9 -0
  67. data/lib/fog/ovirt/requests/compute/mock_files/affinitygroups.xml +17 -0
  68. data/lib/fog/ovirt/requests/compute/remove_from_affinity_group.rb +21 -0
  69. data/lib/fog/ovirt/requests/compute/update_interface.rb +18 -5
  70. data/lib/fog/rackspace/docs/block_storage.md +1 -1
  71. data/lib/fog/rackspace/docs/cdn_v2.md +1 -1
  72. data/lib/fog/rackspace/docs/compute_v2.md +1 -1
  73. data/lib/fog/rackspace/docs/getting_started.md +1 -1
  74. data/lib/fog/rackspace/docs/networking_v2.md +1 -1
  75. data/lib/fog/rackspace/docs/storage.md +1 -1
  76. data/lib/fog/rackspace/examples/README.md +1 -1
  77. data/lib/fog/rackspace/mock_data.rb +48 -48
  78. data/lib/fog/rackspace/models/networking_v2/security_group.rb +32 -0
  79. data/lib/fog/rackspace/models/networking_v2/security_group_rule.rb +38 -0
  80. data/lib/fog/rackspace/models/networking_v2/security_group_rules.rb +23 -0
  81. data/lib/fog/rackspace/models/networking_v2/security_groups.rb +23 -0
  82. data/lib/fog/rackspace/networking_v2.rb +24 -7
  83. data/lib/fog/rackspace/requests/networking_v2/create_security_group.rb +12 -0
  84. data/lib/fog/rackspace/requests/networking_v2/create_security_group_rule.rb +12 -0
  85. data/lib/fog/rackspace/requests/networking_v2/delete_security_group.rb +5 -0
  86. data/lib/fog/rackspace/requests/networking_v2/delete_security_group_rule.rb +5 -0
  87. data/lib/fog/rackspace/requests/networking_v2/list_security_group_rules.rb +5 -0
  88. data/lib/fog/rackspace/requests/networking_v2/list_security_groups.rb +5 -0
  89. data/lib/fog/rackspace/requests/networking_v2/show_security_group.rb +5 -0
  90. data/lib/fog/rackspace/requests/networking_v2/show_security_group_rule.rb +5 -0
  91. data/lib/fog/rackspace/requests/networking_v2/update_security_group.rb +12 -0
  92. data/lib/fog/rackspace/requests/storage/get_object_https_url.rb +1 -1
  93. data/lib/fog/version.rb +1 -1
  94. data/lib/fog/vsphere/requests/compute/cloudinit_to_customspec.rb +13 -4
  95. data/lib/fog/vsphere/requests/compute/vm_clone.rb +19 -6
  96. data/lib/fog/xenserver/requests/compute/create_vdi.rb +16 -6
  97. data/lib/tasks/changelog_task.rb +2 -1
  98. data/spec/fog/account_spec.rb +1 -2
  99. data/spec/fog/billing_spec.rb +1 -2
  100. data/spec/fog/bin/atmos_spec.rb +25 -2
  101. data/spec/fog/bin/aws_spec.rb +1 -2
  102. data/spec/fog/bin/baremetalcloud_spec.rb +25 -2
  103. data/spec/fog/bin/bluebox_spec.rb +47 -2
  104. data/spec/fog/bin/brightbox_spec.rb +1 -2
  105. data/spec/fog/bin/clodo_spec.rb +1 -2
  106. data/spec/fog/bin/cloudsigma_spec.rb +1 -2
  107. data/spec/fog/bin/cloudstack_spec.rb +1 -2
  108. data/spec/fog/bin/digitalocean_spec.rb +1 -2
  109. data/spec/fog/bin/dnsimple_spec.rb +1 -2
  110. data/spec/fog/bin/dnsmadeeasy_spec.rb +1 -2
  111. data/spec/fog/bin/dreamhost_spec.rb +1 -2
  112. data/spec/fog/bin/dynect_spec.rb +1 -2
  113. data/spec/fog/bin/powerdns_spec.rb +9 -0
  114. data/spec/fog/bin_spec.rb +4 -2
  115. data/spec/fog/cdn_spec.rb +1 -2
  116. data/spec/fog/compute_spec.rb +1 -2
  117. data/spec/fog/dns_spec.rb +1 -2
  118. data/spec/fog/identity_spec.rb +1 -2
  119. data/spec/fog/image_spec.rb +1 -2
  120. data/spec/fog/metering_spec.rb +1 -2
  121. data/spec/fog/monitoring_spec.rb +1 -2
  122. data/spec/fog/network_spec.rb +1 -2
  123. data/spec/fog/orchestration_spec.rb +1 -2
  124. data/spec/fog/storage_spec.rb +1 -2
  125. data/spec/fog/support_spec.rb +1 -2
  126. data/spec/fog/volume_spec.rb +1 -2
  127. data/spec/fog/vpn_spec.rb +1 -2
  128. data/spec/fog/xml/connection_spec.rb +1 -2
  129. data/spec/helpers/bin.rb +4 -0
  130. data/spec/spec_helper.rb +15 -0
  131. data/tests/compute/helper.rb +3 -0
  132. data/tests/glesys/requests/compute/helper.rb +66 -2
  133. data/tests/glesys/requests/compute/server_tests.rb +22 -6
  134. data/tests/glesys/requests/compute/ssh_key_tests.rb +47 -0
  135. data/tests/google/credentials_tests.rb +73 -0
  136. data/tests/helper.rb +5 -1
  137. data/tests/linode/requests/compute/linode_tests.rb +76 -3
  138. data/tests/openstack/authenticate_tests.rb +10 -0
  139. data/tests/openstack/models/planning/.gitkeep +0 -0
  140. data/tests/openstack/models/planning/plan_tests.rb +51 -0
  141. data/tests/openstack/models/planning/plans_tests.rb +18 -0
  142. data/tests/openstack/models/planning/role_tests.rb +14 -0
  143. data/tests/openstack/requests/planning/.gitkeep +0 -0
  144. data/tests/openstack/requests/planning/plan_tests.rb +65 -0
  145. data/tests/openstack/requests/planning/role_tests.rb +16 -0
  146. metadata +193 -75
  147. data/lib/fog/bin/atmos.rb +0 -29
  148. data/lib/fog/bin/local.rb +0 -29
  149. data/lib/fog/local.rb +0 -1
  150. data/lib/fog/local/core.rb +0 -9
  151. data/lib/fog/local/models/storage/directories.rb +0 -33
  152. data/lib/fog/local/models/storage/directory.rb +0 -53
  153. data/lib/fog/local/models/storage/file.rb +0 -132
  154. data/lib/fog/local/models/storage/files.rb +0 -84
  155. data/lib/fog/local/storage.rb +0 -96
  156. data/tests/local/models/directories_tests.rb +0 -17
  157. data/tests/local/models/directory_tests.rb +0 -16
  158. data/tests/local/models/file_tests.rb +0 -43
  159. data/tests/local/storage_tests.rb +0 -40
@@ -0,0 +1,64 @@
1
+ module Fog
2
+ module Compute
3
+ class Linode
4
+ class Real
5
+ def image_list(pending=nil, image_id=nil)
6
+ options = {}
7
+ if pending
8
+ options.merge!(:pending => pending)
9
+ end
10
+ if image_id
11
+ options.merge!(:imageId => image_id)
12
+ end
13
+ request(
14
+ :expects => 200,
15
+ :method => 'GET',
16
+ :query => { :api_action => 'image.list' }.merge!(options)
17
+ )
18
+ end
19
+ end
20
+
21
+ class Mock
22
+ def image_list(pending=nil, image_id=nil)
23
+ response = Excon::Response.new
24
+ response.status = 200
25
+ body = {
26
+ "ERRORARRAY" => [],
27
+ "ACTION" => "image.list"
28
+ }
29
+ if image_id
30
+ mock_image = create_mock_image(image_id)
31
+ response.body = body.merge("DATA" => [mock_image])
32
+ else
33
+ mock_images = []
34
+ rand(1..3).times do
35
+ image_id = Fog::Mock.random_numbers(5)
36
+ mock_images << create_mock_image(image_id)
37
+ end
38
+ response.body = body.merge("DATA" => mock_images)
39
+ end
40
+ response
41
+ end
42
+
43
+ private
44
+
45
+ def create_mock_image(image_id, status='available')
46
+ size = rand(1...999999)
47
+ {
48
+ "LAST_USED_DT" => "2014-07-29 12:55:29.0",
49
+ "DESCRIPTION" => "Fog Mock Linode Image #{image_id}",
50
+ "LABEL" => "test_#{image_id}_image",
51
+ "STATUS" => status,
52
+ "TYPE" => "manual",
53
+ "ISPUBLIC" => rand(0...1),
54
+ "CREATE_DT" => "2014-06-29 5:39:19.0",
55
+ "MINSIZE" => Fog::Mock.random_numbers(5),
56
+ "FS_TYPE" => "ext4",
57
+ "CREATOR" => "test_username",
58
+ "IMAGEID" => image_id
59
+ }
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,37 @@
1
+ module Fog
2
+ module Compute
3
+ class Linode
4
+ class Real
5
+ def linode_disk_createfromimage(linode_id, image_id, label, size, password, sshkey)
6
+ request(
7
+ :expects => 200,
8
+ :method => 'GET',
9
+ :query => {
10
+ :api_action => 'linode.disk.createfromimage',
11
+ :linodeId => linode_id,
12
+ :imageId => image_id,
13
+ :label => label,
14
+ :size => size,
15
+ :rootPass => password,
16
+ :rootSSHKey => sshkey
17
+ }
18
+ )
19
+ end
20
+ end
21
+
22
+ class Mock
23
+ def linode_disk_createfromimage(linode_id, image_id, label, size, password, sshkey)
24
+ response = Excon::Response.new
25
+ response.status = 200
26
+ response.body = {
27
+ "ERRORARRAY" => [],
28
+ "ACTION" => "linode.disk.createfromimage",
29
+ "DATA" => { "JobID" => Fog::Mock.random_numbers(4),
30
+ "DiskID" => Fog::Mock.random_numbers(5) }
31
+ }
32
+ response
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,33 @@
1
+ module Fog
2
+ module Compute
3
+ class Linode
4
+ class Real
5
+ def linode_disk_duplicate(linode_id, disk_id)
6
+ request(
7
+ :expects => 200,
8
+ :method => 'GET',
9
+ :query => {
10
+ :api_action => 'linode.disk.duplicate',
11
+ :linodeId => linode_id,
12
+ :diskID => disk_id,
13
+ }
14
+ )
15
+ end
16
+ end
17
+
18
+ class Mock
19
+ def linode_disk_duplicate(linode_id, disk_id)
20
+ response = Excon::Response.new
21
+ response.status = 200
22
+ response.body = {
23
+ "ERRORARRAY" => [],
24
+ "ACTION" => "linode.disk.duplicate",
25
+ "DATA" => { "JobID" => Fog::Mock.random_numbers(4),
26
+ "DiskID" => Fog::Mock.random_numbers(5) }
27
+ }
28
+ response
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ module Fog
2
+ module Compute
3
+ class Linode
4
+ class Real
5
+ def linode_disk_imagize(linode_id, disk_id, description, label)
6
+ request(
7
+ :expects => 200,
8
+ :method => 'GET',
9
+ :query => {
10
+ :api_action => 'linode.disk.imagize',
11
+ :linodeId => linode_id,
12
+ :diskId => disk_id,
13
+ :description => description,
14
+ :label => label
15
+ }
16
+ )
17
+ end
18
+ end
19
+
20
+ class Mock
21
+ def linode_disk_imagize(linode_id, disk_id, description, label)
22
+ response = Excon::Response.new
23
+ response.status = 200
24
+ response.body = {
25
+ "ERRORARRAY" => [],
26
+ "ACTION" => "linode.disk.imagize",
27
+ "DATA" => {
28
+ "JobID" => Fog::Mock.random_numbers(4),
29
+ "ImageID" => Fog::Mock.random_numbers(4)
30
+ }
31
+ }
32
+ response
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ module Fog
2
+ module Compute
3
+ class Linode
4
+ class Real
5
+ def linode_disk_resize(linode_id, disk_id, size)
6
+ request(
7
+ :expects => 200,
8
+ :method => 'GET',
9
+ :query => {
10
+ :api_action => 'linode.disk.resize',
11
+ :linodeId => linode_id,
12
+ :diskId => disk_id,
13
+ :size => size
14
+ }
15
+ )
16
+ end
17
+ end
18
+
19
+ class Mock
20
+ def linode_disk_resize(linode_id, disk_id, size)
21
+ response = Excon::Response.new
22
+ response.status = 200
23
+ response.body = {
24
+ "ERRORARRAY" => [],
25
+ "ACTION" => "linode.disk.resize",
26
+ "DATA" => {
27
+ "JobID" => Fog::Mock.random_numbers(4),
28
+ "DiskID" => Fog::Mock.random_numbers(4)
29
+ }
30
+ }
31
+ response
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ module Fog
2
+ module Compute
3
+ class Linode
4
+ class Real
5
+ def linode_disk_update(linode_id, disk_id, label, isreadonly)
6
+ request(
7
+ :expects => 200,
8
+ :method => 'GET',
9
+ :query => {
10
+ :api_action => 'linode.disk.update',
11
+ :linodeId => linode_id,
12
+ :diskId => disk_id,
13
+ :label => label,
14
+ :isReadOnly => isreadonly
15
+ }
16
+ )
17
+ end
18
+ end
19
+
20
+ class Mock
21
+ def linode_disk_update(linode_id, disk_id, label, isreadonly)
22
+ response = Excon::Response.new
23
+ response.status = 200
24
+ response.body = {
25
+ "ERRORARRAY" => [],
26
+ "ACTION" => "linode.disk.update",
27
+ "DATA" => { "DiskID" => Fog::Mock.random_numbers(5) }
28
+ }
29
+ response
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -7,3 +7,4 @@ require 'fog/openstack/orchestration'
7
7
  require 'fog/openstack/storage'
8
8
  require 'fog/openstack/volume'
9
9
  require 'fog/openstack/baremetal'
10
+ require 'fog/openstack/planning'
@@ -102,6 +102,9 @@ module Fog
102
102
  request :remove_flavor_access
103
103
  request :list_tenants_with_flavor_access
104
104
 
105
+ # Hypervisor
106
+ request :get_hypervisor_statistics
107
+
105
108
  # Metadata
106
109
  request :list_metadata
107
110
  request :get_metadata
@@ -247,6 +250,7 @@ module Fog
247
250
 
248
251
  def initialize(options={})
249
252
  @openstack_username = options[:openstack_username]
253
+ @openstack_domain = options[:openstack_domain]
250
254
  @openstack_auth_uri = URI.parse(options[:openstack_auth_url])
251
255
 
252
256
  @current_tenant = options[:openstack_tenant]
@@ -286,6 +290,7 @@ module Fog
286
290
  attr_reader :auth_token_expiration
287
291
  attr_reader :current_user
288
292
  attr_reader :current_tenant
293
+ attr_reader :openstack_domain
289
294
 
290
295
  def initialize(options={})
291
296
  @openstack_auth_token = options[:openstack_auth_token]
@@ -296,6 +301,7 @@ module Fog
296
301
  missing_credentials = Array.new
297
302
  @openstack_api_key = options[:openstack_api_key]
298
303
  @openstack_username = options[:openstack_username]
304
+ @openstack_domain = options[:openstack_domain]
299
305
 
300
306
  missing_credentials << :openstack_api_key unless @openstack_api_key
301
307
  missing_credentials << :openstack_username unless @openstack_username
@@ -303,6 +309,7 @@ module Fog
303
309
  end
304
310
 
305
311
  @openstack_tenant = options[:openstack_tenant]
312
+ @openstack_domain = options[:openstack_domain] || 'Default'
306
313
  @openstack_auth_uri = URI.parse(options[:openstack_auth_url])
307
314
  @openstack_management_url = options[:openstack_management_url]
308
315
  @openstack_must_reauthenticate = false
@@ -325,6 +332,7 @@ module Fog
325
332
 
326
333
  def credentials
327
334
  { :provider => 'openstack',
335
+ :openstack_domain => @openstack_domain,
328
336
  :openstack_auth_url => @openstack_auth_uri.to_s,
329
337
  :openstack_auth_token => @auth_token,
330
338
  :openstack_management_url => @openstack_management_url,
@@ -380,6 +388,7 @@ module Fog
380
388
  options = {
381
389
  :openstack_api_key => @openstack_api_key,
382
390
  :openstack_username => @openstack_username,
391
+ :openstack_domain => @openstack_domain,
383
392
  :openstack_auth_token => @openstack_must_reauthenticate ? nil : @auth_token,
384
393
  :openstack_auth_uri => @openstack_auth_uri,
385
394
  :openstack_region => @openstack_region,
@@ -393,6 +402,8 @@ module Fog
393
402
  if @openstack_auth_uri.path =~ /\/v2.0/
394
403
 
395
404
  credentials = Fog::OpenStack.authenticate_v2(options, @connection_options)
405
+ elsif @openstack_auth_uri.path =~ /\/v3/
406
+ credentials = Fog::OpenStack.authenticate_v3(options, @connection_options)
396
407
  else
397
408
  credentials = Fog::OpenStack.authenticate_v1(options, @connection_options)
398
409
  end
@@ -412,7 +423,7 @@ module Fog
412
423
  @path, @tenant_id = uri.path.scan(/(\/.*)\/(.*)/).flatten
413
424
 
414
425
  @path.sub!(/\/$/, '')
415
- unless @path.match(/1\.1|v2/)
426
+ unless @path.match(/1\.1|v2|v3/)
416
427
  raise Fog::OpenStack::Errors::ServiceUnavailable.new(
417
428
  "OpenStack binding only supports version 2 (a.k.a. 1.1)")
418
429
  end
@@ -51,11 +51,16 @@ module Fog
51
51
  service(:metering, 'Metering')
52
52
  service(:orchestration, 'Orchestration')
53
53
  service(:baremetal, 'Baremetal')
54
+ service(:planning, 'Planning')
54
55
 
55
56
  def self.authenticate(options, connection_options = {})
56
57
  case options[:openstack_auth_uri].path
57
58
  when /v1(\.\d+)?/
58
59
  authenticate_v1(options, connection_options)
60
+ when /v2(\.\d+)?/
61
+ authenticate_v2(options, connection_options)
62
+ when /v3(\.\d+)?/
63
+ authenticate_v3(options, connection_options)
59
64
  else
60
65
  authenticate_v2(options, connection_options)
61
66
  end
@@ -168,13 +173,113 @@ module Fog
168
173
  }
169
174
  end
170
175
 
176
+ # Keystone Style Auth
177
+ def self.authenticate_v3(options, connection_options = {})
178
+ uri = options[:openstack_auth_uri]
179
+ tenant_name = options[:openstack_tenant]
180
+ service_type = options[:openstack_service_type]
181
+ service_name = options[:openstack_service_name]
182
+ identity_service_type = options[:openstack_identity_service_type]
183
+ endpoint_type = (options[:openstack_endpoint_type] || 'public').to_s
184
+ openstack_region = options[:openstack_region]
185
+ domain_name = options[:openstack_domain]
186
+
187
+ body, token_headers = retrieve_tokens_v3(options, connection_options)
188
+
189
+ service = get_service(body, service_type, service_name)
190
+
191
+ options[:unscoped_token] = token_headers['X-Subject-Token']
192
+
193
+ unless service
194
+ unless tenant_name
195
+ response = Fog::Core::Connection.new(
196
+ "#{uri.scheme}://#{uri.host}:#{uri.port}/v3/projects", false, connection_options).request({
197
+ :expects => [200, 204],
198
+ :headers => {'Content-Type' => 'application/json',
199
+ 'Accept' => 'application/json',
200
+ 'X-Auth-Token' => token_headers['X-Subject-Token']},
201
+ :method => 'GET'
202
+ })
203
+ body = Fog::JSON.decode(response.body)
204
+ if body['projects'].empty?
205
+ raise Fog::Errors::NotFound.new('No Tenant Found')
206
+ else
207
+ options[:openstack_tenant] = body['projects'].first['name']
208
+ end
209
+
210
+ end
211
+ body, token_headers = retrieve_tokens_v3(options, connection_options)
212
+ service = get_service(body, service_type, service_name)
213
+ end
214
+
215
+ service['endpoints'] = service['endpoints'].select do |endpoint|
216
+ endpoint['region'] == openstack_region
217
+ end if openstack_region
218
+
219
+ if service['endpoints'].empty?
220
+ raise Fog::Errors::NotFound.new("No endpoints available for region '#{openstack_region}'")
221
+ end if openstack_region
222
+
223
+ unless service
224
+ available = body['token']['catalog'].map { |endpoint|
225
+ endpoint['type']
226
+ }.sort.join ', '
227
+
228
+ missing = service_type.join ', '
229
+
230
+ message = "Could not find service #{missing}. Have #{available}"
231
+
232
+ raise Fog::Errors::NotFound, message
233
+ end
234
+
235
+ admin = false
236
+ body['token']['roles'].each do |r|
237
+ admin = true if r["name"] == "admin"
238
+ end
239
+
240
+ if service['endpoints'].count > 1 and not admin
241
+ regions = service["endpoints"].map{ |e| e['region'] }.uniq.join(',')
242
+ raise Fog::Errors::NotFound.new("Multiple regions available choose one of these '#{regions}'")
243
+ end
244
+
245
+ identity_service = get_service(body, identity_service_type) if identity_service_type
246
+ tenant = body['token']['project']['name']
247
+ user = body['token']['user']['name']
248
+ endpoint_type = 'public'
249
+
250
+ management_url = service['endpoints'].find{|s| s["interface"][endpoint_type]}["url"]
251
+ identity_url = identity_service['endpoints'].find{|s| s["interface"]["public"]}["url"] if identity_service
252
+ {
253
+ :user => user,
254
+ :tenant => tenant,
255
+ :identity_public_endpoint => identity_url,
256
+ :server_management_url => management_url,
257
+ :token => token_headers['X-Subject-Token'],
258
+ :expires => body['token']['expires_at'],
259
+ :current_user_id => body['token']['user']['id'],
260
+ :unscoped_token => options[:unscoped_token]
261
+ }
262
+ end
263
+
264
+
171
265
  def self.get_service(body, service_type=[], service_name=nil)
172
- body['access']['serviceCatalog'].find do |s|
173
- if service_name.nil? or service_name.empty?
174
- service_type.include?(s['type'])
175
- else
176
- service_type.include?(s['type']) and s['name'] == service_name
266
+ if not body['access'].nil?
267
+ body['access']['serviceCatalog'].find do |s|
268
+ if service_name.nil? or service_name.empty?
269
+ service_type.include?(s['type'])
270
+ else
271
+ service_type.include?(s['type']) and s['name'] == service_name
272
+ end
177
273
  end
274
+ elsif not body['token']['catalog'].nil?
275
+ body['token']['catalog'].find do |s|
276
+ if service_name.nil? or service_name.empty?
277
+ service_type.include?(s['type'])
278
+ else
279
+ service_type.include?(s['type']) and s['name'] == service_name
280
+ end
281
+ end
282
+
178
283
  end
179
284
  end
180
285
 
@@ -211,6 +316,55 @@ module Fog
211
316
  Fog::JSON.decode(response.body)
212
317
  end
213
318
 
319
+ def self.retrieve_tokens_v3(options, connection_options = {})
320
+ api_key = options[:openstack_api_key].to_s
321
+ username = options[:openstack_username].to_s
322
+ tenant_name = options[:openstack_tenant].to_s
323
+ auth_token = options[:openstack_auth_token] || options[:unscoped_token]
324
+ uri = options[:openstack_auth_uri]
325
+ domain = options[:openstack_domain]
326
+
327
+ connection = Fog::Core::Connection.new(uri.to_s, false, connection_options)
328
+ request_body = {:auth => Hash.new}
329
+
330
+ if auth_token
331
+ request_body[:auth][:token] = {
332
+ :id => auth_token
333
+ }
334
+ else
335
+ request_body[:auth][:identity] = {
336
+ :methods => ["password"],
337
+ :password => {
338
+ :user => {
339
+ :domain => {
340
+ :name => domain
341
+ },
342
+ :name => username,
343
+ :password => api_key
344
+ }
345
+ }
346
+ }
347
+ request_body[:auth][:scope] = {
348
+ :project => {
349
+ :domain => {
350
+ :name => domain
351
+ },
352
+ :id => tenant_name
353
+ }
354
+ }
355
+ end
356
+
357
+ response = connection.request({
358
+ :expects => [201],
359
+ :headers => {'Content-Type' => 'application/json'},
360
+ :body => Fog::JSON.encode(request_body),
361
+ :method => 'POST',
362
+ :path => (uri.path and not uri.path.empty?) ? uri.path : 'v3'
363
+ })
364
+
365
+ return Fog::JSON.decode(response.body), response.headers
366
+ end
367
+
214
368
  def self.get_supported_version(supported_versions, uri, auth_token, connection_options = {})
215
369
  connection = Fog::Core::Connection.new("#{uri.scheme}://#{uri.host}:#{uri.port}", false, connection_options)
216
370
  response = connection.request({