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
@@ -24,7 +24,8 @@
24
24
  rvm use ${version} > /dev/null 2>&1
25
25
  echo "Running tests based on Ruby ${version}..."
26
26
  ruby --version
27
- gem install bundler --version '~> 1'
27
+ gem install bundler
28
+ gem update bundler
28
29
  bundle install --jobs=3 --retry=3
29
30
  bundle exec rake test TESTOPTS="--verbose"
30
31
  done
@@ -0,0 +1,252 @@
1
+ require 'test_helper'
2
+
3
+ describe Fog::OpenStack::Auth::Catalog::V3 do
4
+ CATALOGV3 = [
5
+ {
6
+ "endpoints" => [
7
+ {
8
+ "region_id" => "regionOne",
9
+ "url" => "http://localhost:9696",
10
+ "region" => "regionOne",
11
+ "interface" => "internal",
12
+ "id" => "id_endpoint1_internal"
13
+ },
14
+ {
15
+ "region_id" => "regionOne",
16
+ "url" => "http://localhost:9696",
17
+ "region" => "regionOne",
18
+ "interface" => "public",
19
+ "id" => "id_endpoint1_public"
20
+ },
21
+ {
22
+ "region_id" => "regionOne",
23
+ "url" => "http://localhost:9696",
24
+ "region" => "regionOne",
25
+ "interface" => "admin",
26
+ "id" => "id_endpoint1_admin"
27
+ }
28
+ ],
29
+ "type" => "network",
30
+ "id" => "id1",
31
+ "name" => "neutron"
32
+ },
33
+ {
34
+ "endpoints" => [
35
+ {
36
+ "region_id" => "regionOne",
37
+ "url" => "http://localhost:9292",
38
+ "region" => "regionOne",
39
+ "interface" => "internal",
40
+ "id" => "id_endpoint1_internal"
41
+ },
42
+ {
43
+ "region_id" => "regionOne",
44
+ "url" => "http://localhost:9292",
45
+ "region" => "regionOne",
46
+ "interface" => "public",
47
+ "id" => "id_endpoint1_public"
48
+ },
49
+ {
50
+ "region_id" => "regionOne",
51
+ "url" => "http://localhost:9292",
52
+ "region" => "regionOne",
53
+ "interface" => "admin",
54
+ "id" => "id_endpoint1_admin"
55
+ }
56
+ ],
57
+ "type" => "image",
58
+ "id" => "id2",
59
+ "name" => "glance"
60
+ },
61
+ {
62
+ "endpoints" => [
63
+ {
64
+ "region_id" => "regionOne",
65
+ "url" => "http://localhost:5000",
66
+ "region" => "regionOne",
67
+ "interface" => "internal",
68
+ "id" => "id_endpoint1_internal"
69
+ },
70
+ {
71
+ "region_id" => "regionOne",
72
+ "url" => "http://localhost:5000",
73
+ "region" => "regionOne",
74
+ "interface" => "public",
75
+ "id" => "id_endpoint1_public"
76
+ },
77
+ {
78
+ "region_id" => "regionOne",
79
+ "url" => "http://localhost:35357",
80
+ "region" => "regionOne",
81
+ "interface" => "admin",
82
+ "id" => "id_endpoint1_admin"
83
+ }
84
+ ],
85
+ "type" => "identity",
86
+ "id" => "id3",
87
+ "name" => "keystone"
88
+ },
89
+ {
90
+ "endpoints" => [
91
+ {
92
+ "region_id" => "regionOne",
93
+ "url" => "http://localhost2:5000",
94
+ "region" => "regionTwo",
95
+ "interface" => "internal",
96
+ "id" => "id_endpoint1_internal"
97
+ },
98
+ {
99
+ "region_id" => "regionTwo",
100
+ "url" => "http://localhost2:5000",
101
+ "region" => "regionTwo",
102
+ "interface" => "public",
103
+ "id" => "id_endpoint1_public"
104
+ },
105
+ {
106
+ "region_id" => "regionTwo",
107
+ "url" => "http://localhost2:35357",
108
+ "region" => "regionTwo",
109
+ "interface" => "admin",
110
+ "id" => "id_endpoint1_admin"
111
+ }
112
+ ],
113
+ "type" => "identity",
114
+ "id" => "id3",
115
+ "name" => "keystone"
116
+ }
117
+ ].freeze
118
+
119
+ let(:payload) do
120
+ CATALOGV3
121
+ end
122
+
123
+ describe '#get_endpoint_url' do
124
+ it 'with matching name, interface and region' do
125
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
126
+ catalog.get_endpoint_url('identity', 'admin', 'regionTwo').must_equal 'http://localhost2:35357'
127
+ end
128
+
129
+ it 'with matching name and interface using avail region' do
130
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
131
+ catalog.get_endpoint_url('network', %w[dummy admin]).must_equal 'http://localhost:9696'
132
+ end
133
+
134
+ it 'with matching name and interface list' do
135
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
136
+ catalog.get_endpoint_url('network', %w[dummy admin]).must_equal 'http://localhost:9696'
137
+ end
138
+
139
+ it 'with matching name and interface and several regions available' do
140
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
141
+ proc do
142
+ catalog.get_endpoint_url('identity', 'admin')
143
+ end.must_raise Fog::OpenStack::Auth::Catalog::EndpointError
144
+ end
145
+
146
+ it 'with unmatched name for service type' do
147
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
148
+ proc do
149
+ catalog.get_endpoint_url('service', 'public')
150
+ end.must_raise Fog::OpenStack::Auth::Catalog::ServiceTypeError
151
+ end
152
+
153
+ it 'with unmatched region' do
154
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
155
+ proc do
156
+ catalog.get_endpoint_url('identity', 'admin', 'regionOther')
157
+ end.must_raise Fog::OpenStack::Auth::Catalog::EndpointError
158
+ end
159
+
160
+ it 'with unmatched interface' do
161
+ catalog = Fog::OpenStack::Auth::Catalog::V3.new(payload)
162
+ proc do
163
+ catalog.get_endpoint_url('identity', 'private')
164
+ end.must_raise Fog::OpenStack::Auth::Catalog::EndpointError
165
+ end
166
+ end
167
+ end
168
+
169
+ describe Fog::OpenStack::Auth::Catalog::V2 do
170
+ CATALOGV2 = [
171
+ {
172
+ 'endpoints' => [{
173
+ 'adminURL' => 'http://localhost',
174
+ 'region' => 'regionOne',
175
+ 'internalURL' => 'http://localhost:8888/v2.0',
176
+ 'id' => 'id_endpoints',
177
+ 'publicURL' => 'http://localhost'
178
+ }],
179
+ 'endpoints_links' => [],
180
+ 'type' => 'identity',
181
+ 'name' => 'keystone'
182
+ },
183
+ {
184
+ 'endpoints' => [{
185
+ 'adminURL' => 'http://localhost',
186
+ 'region' => 'regionTwo',
187
+ 'internalURL' => 'http://localhost:9999/v2.0',
188
+ 'id' => 'id_endpoints',
189
+ 'publicURL' => 'http://localhost'
190
+ }],
191
+ 'endpoints_links' => [],
192
+ 'type' => 'identity',
193
+ 'name' => 'keystone'
194
+ },
195
+ {
196
+ 'endpoints' => [{
197
+ 'adminURL' => 'http://localhost',
198
+ 'region' => 'regionOne',
199
+ 'internalURL' => 'http://localhost:7777/v1.0',
200
+ 'id' => 'id_endpoints',
201
+ 'publicURL' => 'http://localhost'
202
+ }],
203
+ 'endpoints_links' => [],
204
+ 'type' => 'compute',
205
+ 'name' => 'nova'
206
+ }
207
+ ].freeze
208
+
209
+ let(:payload) do
210
+ CATALOGV2
211
+ end
212
+
213
+ describe '#get_endpoint_url' do
214
+ it 'match name, interface and region' do
215
+ catalog = Fog::OpenStack::Auth::Catalog::V2.new(payload)
216
+ catalog.get_endpoint_url('identity', 'internal', 'regionTwo').must_equal 'http://localhost:9999/v2.0'
217
+ end
218
+
219
+ it 'match name, interface and unique region available' do
220
+ catalog = Fog::OpenStack::Auth::Catalog::V2.new(payload)
221
+ catalog.get_endpoint_url('compute', 'internal').must_equal 'http://localhost:7777/v1.0'
222
+ end
223
+
224
+ it 'fails when multiple region match' do
225
+ catalog = Fog::OpenStack::Auth::Catalog::V2.new(payload)
226
+ proc do
227
+ catalog.get_endpoint_url('identity', 'admin')
228
+ end.must_raise Fog::OpenStack::Auth::Catalog::EndpointError
229
+ end
230
+
231
+ it 'with unmatched arguments' do
232
+ catalog = Fog::OpenStack::Auth::Catalog::V2.new(payload)
233
+ proc do
234
+ catalog.get_endpoint_url('test', 'unknown', 'regionOther')
235
+ end.must_raise Fog::OpenStack::Auth::Catalog::ServiceTypeError
236
+ end
237
+
238
+ it 'with unmatched region' do
239
+ catalog = Fog::OpenStack::Auth::Catalog::V2.new(payload)
240
+ proc do
241
+ catalog.get_endpoint_url('identity', 'admin', 'regionOther')
242
+ end.must_raise Fog::OpenStack::Auth::Catalog::EndpointError
243
+ end
244
+
245
+ it 'with unmatched interface' do
246
+ catalog = Fog::OpenStack::Auth::Catalog::V2.new(payload)
247
+ proc do
248
+ catalog.get_endpoint_url('identity', 'private', 'regionTwo')
249
+ end.must_raise Fog::OpenStack::Auth::Catalog::EndpointError
250
+ end
251
+ end
252
+ end
@@ -0,0 +1,115 @@
1
+ require 'test_helper'
2
+ require 'fog/openstack/auth/name'
3
+
4
+ describe Fog::OpenStack::Auth::Name do
5
+ describe 'creates' do
6
+ it 'when id and name are provided' do
7
+ name = Fog::OpenStack::Auth::Name.new('default', 'Default')
8
+ name.id.must_equal 'default'
9
+ name.name.must_equal 'Default'
10
+ end
11
+
12
+ it 'when id is null' do
13
+ name = Fog::OpenStack::Auth::Name.new(nil, 'Default')
14
+ name.id.must_be_nil
15
+ name.name.must_equal 'Default'
16
+ end
17
+
18
+ it 'when name is null' do
19
+ name = Fog::OpenStack::Auth::Name.new('default', nil)
20
+ name.id.must_equal 'default'
21
+ name.name.must_be_nil
22
+ end
23
+
24
+ it 'when both id and name is null' do
25
+ name = Fog::OpenStack::Auth::Name.new(nil, nil)
26
+ name.name.must_be_nil
27
+ end
28
+ end
29
+
30
+ describe '#to_h' do
31
+ it 'returns the hash of provided attribute' do
32
+ name = Fog::OpenStack::Auth::Name.new('default', 'Default')
33
+ name.to_h(:id).must_equal(:id => 'default')
34
+ name.to_h(:name).must_equal(:name => 'Default')
35
+ end
36
+ end
37
+ end
38
+
39
+ describe Fog::OpenStack::Auth::User do
40
+ describe '#password' do
41
+ it 'set/get password' do
42
+ user = Fog::OpenStack::Auth::User.new('user_id', 'User')
43
+ user.password = 'secret'
44
+ user.identity.must_equal(:user => {:id => 'user_id', :password => 'secret'})
45
+ end
46
+ end
47
+
48
+ describe '#identity' do
49
+ describe 'succesful' do
50
+ it "with user id and user name" do
51
+ user = Fog::OpenStack::Auth::User.new('user_id', 'User')
52
+ user.password = 'secret'
53
+ user.identity.must_equal(:user => {:id => 'user_id', :password => 'secret'})
54
+ end
55
+
56
+ it 'with user name and user domain name' do
57
+ user = Fog::OpenStack::Auth::User.new(nil, 'User')
58
+ user.password = 'secret'
59
+ user.domain = Fog::OpenStack::Auth::Name.new('default', nil)
60
+ user.identity.must_equal(:user => {:name => 'User', :domain => {:id => 'default'}, :password => 'secret'})
61
+ end
62
+
63
+ it 'with user name and domain name' do
64
+ user = Fog::OpenStack::Auth::User.new(nil, 'User')
65
+ user.password = 'secret'
66
+ user.domain = Fog::OpenStack::Auth::Name.new(nil, 'Default')
67
+ user.identity.must_equal(:user => {:name => 'User', :domain => {:name => 'Default'}, :password => 'secret'})
68
+ end
69
+ end
70
+
71
+ describe 'raises an error' do
72
+ it 'raises an error when password is missing' do
73
+ proc do
74
+ user = Fog::OpenStack::Auth::User.new('user_id', 'User')
75
+ user.identity
76
+ end.must_raise Fog::OpenStack::Auth::CredentialsError
77
+ end
78
+
79
+ it 'with only user name and no domain' do
80
+ proc do
81
+ user = Fog::OpenStack::Auth::User.new(nil, 'User')
82
+ user.identity
83
+ end.must_raise Fog::OpenStack::Auth::CredentialsError
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ describe Fog::OpenStack::Auth::ProjectScope do
90
+ describe '#identity' do
91
+ it "when id is provided it doesn't require domain" do
92
+ project = Fog::OpenStack::Auth::ProjectScope.new('project_id', 'Project')
93
+ project.identity.must_equal(:project => {:id => 'project_id'})
94
+ end
95
+
96
+ it 'when id is nul and name is provided it uses domain id' do
97
+ project = Fog::OpenStack::Auth::ProjectScope.new(nil, 'Project')
98
+ project.domain = Fog::OpenStack::Auth::Name.new('default', nil)
99
+ project.identity.must_equal(:project => {:name => 'Project', :domain => {:id => 'default'}})
100
+ end
101
+
102
+ it 'when id is nul and name is provided it uses domain name' do
103
+ project = Fog::OpenStack::Auth::ProjectScope.new(nil, 'Project')
104
+ project.domain = Fog::OpenStack::Auth::Name.new(nil, 'Default')
105
+ project.identity.must_equal(:project => {:name => 'Project', :domain => {:name => 'Default'}})
106
+ end
107
+
108
+ it 'raises an error with no project id and no domain are provided' do
109
+ proc do
110
+ project = Fog::OpenStack::Auth::ProjectScope.new(nil, 'Project')
111
+ project.identity
112
+ end.must_raise Fog::OpenStack::Auth::CredentialsError
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,478 @@
1
+ require 'test_helper'
2
+ require 'auth_helper'
3
+
4
+ describe Fog::OpenStack::Auth::Token do
5
+ describe 'V3' do
6
+ describe '#new' do
7
+ it 'fails when missing credentials' do
8
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
9
+ to_return(
10
+ :status => 200,
11
+ :body => "{\"token\":{\"catalog\":[]}}",
12
+ :headers => {'x-subject-token'=>'token_data'}
13
+ )
14
+
15
+ proc do
16
+ Fog::OpenStack::Auth::Token.build({})
17
+ end.must_raise Fog::OpenStack::Auth::Token::URLError
18
+ end
19
+
20
+ describe 'using the password method' do
21
+ describe 'with a project scope' do
22
+ it 'authenticates using a project id' do
23
+ auth = {
24
+ :openstack_auth_url => 'http://localhost/identity',
25
+ :openstack_userid => 'user_id',
26
+ :openstack_api_key => 'secret',
27
+ :openstack_project_id => 'project_id'
28
+ }
29
+
30
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
31
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":{\"user\":\
32
+ {\"id\":\"user_id\",\"password\":\"secret\"}}},\"scope\":{\"project\":{\"id\":\"project_id\"}}}}").
33
+ to_return(
34
+ :status => 200,
35
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
36
+ :headers => {'x-subject-token'=>'token_data_v3'}
37
+ )
38
+
39
+ token = Fog::OpenStack::Auth::Token.build(auth)
40
+ token.get.must_equal 'token_data_v3'
41
+ end
42
+
43
+ it 'authenticates using a project name and a project domain id' do
44
+ auth = {
45
+ :openstack_auth_url => 'http://localhost/identity',
46
+ :openstack_userid => 'user_id',
47
+ :openstack_api_key => 'secret',
48
+ :openstack_project_name => 'project',
49
+ :openstack_project_domain_id => 'project_domain_id'
50
+ }
51
+
52
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
53
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":{\"user\":{\"id\":\
54
+ \"user_id\",\"password\":\"secret\"}}},\"scope\":{\"project\":{\"name\":\"project\",\"domain\":{\"id\":\
55
+ \"project_domain_id\"}}}}}").
56
+ to_return(
57
+ :status => 200,
58
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
59
+ :headers => {'x-subject-token'=>'token_data'}
60
+ )
61
+
62
+ token = Fog::OpenStack::Auth::Token.build(auth)
63
+ token.get.must_equal 'token_data'
64
+ end
65
+
66
+ it 'authenticates using a project name and a project domain name' do
67
+ auth = {
68
+ :openstack_auth_url => 'http://localhost/identity',
69
+ :openstack_username => 'user',
70
+ :openstack_user_domain_name => 'user_domain',
71
+ :openstack_api_key => 'secret',
72
+ :openstack_project_name => 'project',
73
+ :openstack_project_domain_name => 'project_domain'
74
+ }
75
+
76
+ stub_request(:post, "http://localhost/identity/v3/auth/tokens").
77
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":{\"user\":{\"name\":\
78
+ \"user\",\"domain\":{\"name\":\"user_domain\"},\"password\":\"secret\"}}},\"scope\":{\"project\":{\"name\":\"project\"\
79
+ ,\"domain\":{\"name\":\"project_domain\"}}}}}").
80
+ to_return(
81
+ :status => 200,
82
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
83
+ :headers => {'x-subject-token'=>'token_data'}
84
+ )
85
+
86
+ token = Fog::OpenStack::Auth::Token.build(auth)
87
+ token.get.must_equal 'token_data'
88
+ end
89
+ end
90
+
91
+ describe 'with a domain scope' do
92
+ it 'authenticates using a domain id' do
93
+ auth = {
94
+ :openstack_auth_url => 'http://localhost/identity',
95
+ :openstack_userid => 'user_id',
96
+ :openstack_api_key => 'secret',
97
+ :openstack_domain_id => 'domain_id'
98
+ }
99
+
100
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
101
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":{\"user\":{\"id\":\
102
+ \"user_id\",\"password\":\"secret\"}}},\"scope\":{\"domain\":{\"id\":\"domain_id\"}}}}").
103
+ to_return(
104
+ :status => 200,
105
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
106
+ :headers => {'x-subject-token'=>'token_data'}
107
+ )
108
+
109
+ token = Fog::OpenStack::Auth::Token.build(auth)
110
+ token.get.must_equal 'token_data'
111
+ end
112
+
113
+ it 'authenticates using a domain name' do
114
+ auth = {
115
+ :openstack_auth_url => 'http://localhost/identity',
116
+ :openstack_userid => 'user_id',
117
+ :openstack_api_key => 'secret',
118
+ :openstack_domain_name => 'domain'
119
+ }
120
+
121
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
122
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":{\"user\":{\"id\":\
123
+ \"user_id\",\"password\":\"secret\"}}},\"scope\":{\"domain\":{\"name\":\"domain\"}}}}").
124
+ to_return(
125
+ :status => 200,
126
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
127
+ :headers => {'x-subject-token'=>'token_data'}
128
+ )
129
+
130
+ token = Fog::OpenStack::Auth::Token.build(auth)
131
+ token.get.must_equal 'token_data'
132
+ end
133
+ end
134
+
135
+ describe 'unscoped' do
136
+ it 'authenticates' do
137
+ auth = {
138
+ :openstack_auth_url => 'http://localhost/identity',
139
+ :openstack_userid => 'user_id',
140
+ :openstack_api_key => 'secret',
141
+ }
142
+
143
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
144
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":{\"user\":{\"id\":\
145
+ \"user_id\",\"password\":\"secret\"}}}}}").
146
+ to_return(
147
+ :status => 200,
148
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
149
+ :headers => {'x-subject-token'=>'token_data'}
150
+ )
151
+
152
+ token = Fog::OpenStack::Auth::Token.build(auth)
153
+ token.get.must_equal 'token_data'
154
+ end
155
+ end
156
+ end
157
+
158
+ describe 'using the token method' do
159
+ describe 'unscoped' do
160
+ it 'authenticates using a project id' do
161
+ auth = {
162
+ :openstack_auth_url => 'http://localhost/identity',
163
+ :openstack_auth_token => 'token',
164
+ }
165
+
166
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
167
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"token\"}}}}").
168
+ to_return(
169
+ :status => 200,
170
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
171
+ :headers => {'x-subject-token'=>'token_data'}
172
+ )
173
+
174
+ token = Fog::OpenStack::Auth::Token.build(auth)
175
+ token.get.must_equal 'token_data'
176
+ end
177
+ end
178
+
179
+ describe 'with a project scope' do
180
+ it 'authenticates using a project id' do
181
+ auth = {
182
+ :openstack_auth_url => 'http://localhost/identity',
183
+ :openstack_auth_token => 'token',
184
+ :openstack_project_id => 'project_id'
185
+ }
186
+
187
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
188
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"token\"}},\
189
+ \"scope\":{\"project\":{\"id\":\"project_id\"}}}}").
190
+ to_return(
191
+ :status => 200,
192
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
193
+ :headers => {'x-subject-token'=>'token_data'}
194
+ )
195
+
196
+ token = Fog::OpenStack::Auth::Token.build(auth)
197
+ token.get.must_equal 'token_data'
198
+ end
199
+
200
+ it 'authenticates using a project name and a project domain id' do
201
+ auth = {
202
+ :openstack_auth_url => 'http://localhost/identity',
203
+ :openstack_auth_token => 'token',
204
+ :openstack_project_name => 'project',
205
+ :openstack_project_domain_id => 'domain_id'
206
+ }
207
+
208
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
209
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"token\"}},\
210
+ \"scope\":{\"project\":{\"name\":\"project\",\"domain\":{\"id\":\"domain_id\"}}}}}").
211
+ to_return(
212
+ :status => 200,
213
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
214
+ :headers => {'x-subject-token'=>'token_data'}
215
+ )
216
+
217
+ token = Fog::OpenStack::Auth::Token.build(auth)
218
+ token.get.must_equal 'token_data'
219
+ end
220
+ end
221
+
222
+ describe 'with a domain scope' do
223
+ it 'authenticates using a domain id' do
224
+ auth = {
225
+ :openstack_auth_url => 'http://localhost/identity',
226
+ :openstack_auth_token => 'token',
227
+ :openstack_domain_id => 'domain_id'
228
+ }
229
+
230
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
231
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"token\"}},\
232
+ \"scope\":{\"domain\":{\"id\":\"domain_id\"}}}}").
233
+ to_return(
234
+ :status => 200,
235
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
236
+ :headers => {'x-subject-token'=>'token_data'}
237
+ )
238
+
239
+ token = Fog::OpenStack::Auth::Token.build(auth)
240
+ token.get.must_equal 'token_data'
241
+ end
242
+
243
+ it 'authenticates using a domain name' do
244
+ auth = {
245
+ :openstack_auth_url => 'http://localhost/identity',
246
+ :openstack_auth_token => 'token',
247
+ :openstack_domain_name => 'domain'
248
+ }
249
+
250
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
251
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"token\"}},\
252
+ \"scope\":{\"domain\":{\"name\":\"domain\"}}}}").
253
+ to_return(
254
+ :status => 200,
255
+ :body => JSON.dump(auth_response_v3('identity', 'keystone')),
256
+ :headers => {'x-subject-token'=>'token_data'}
257
+ )
258
+
259
+ token = Fog::OpenStack::Auth::Token.build(auth)
260
+ token.get.must_equal 'token_data'
261
+ end
262
+ end
263
+ end
264
+ end
265
+
266
+ describe 'when authenticated' do
267
+ let(:authv3_creds) do
268
+ {
269
+ :openstack_auth_url => 'http://localhost/identity',
270
+ :openstack_username => 'admin',
271
+ :openstack_api_key => 'secret',
272
+ :openstack_project_name => 'admin',
273
+ :openstack_project_domain_id => 'default'
274
+ }
275
+ end
276
+
277
+ describe '#get' do
278
+ it 'when token has not expired' do
279
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
280
+ to_return(
281
+ :status => 200,
282
+ :body => "{\"token\":{\"catalog\":[\"catalog_data\"]}}",
283
+ :headers => {'x-subject-token'=>'token_data'}
284
+ )
285
+
286
+ token = Fog::OpenStack::Auth::Token.build(authv3_creds)
287
+ token.stub :expired?, false do
288
+ token.get.must_equal 'token_data'
289
+ end
290
+ end
291
+
292
+ it 'when token has expired' do
293
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
294
+ to_return(
295
+ :status => 200,
296
+ :body => "{\"token\":{\"catalog\":[\"catalog_data\"]}}",
297
+ :headers => {'x-subject-token'=>'token_data'}
298
+ )
299
+
300
+ token = Fog::OpenStack::Auth::Token.build(authv3_creds)
301
+ token.stub :expired?, true do
302
+ token.get.must_equal 'token_data'
303
+ end
304
+ end
305
+ end
306
+
307
+ it '#catalog' do
308
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
309
+ to_return(
310
+ :status => 200,
311
+ :body => "{\"token\":{\"catalog\":[\"catalog_data\"]}}",
312
+ :headers => {'x-subject-token'=>'token_data'}
313
+ )
314
+
315
+ token = Fog::OpenStack::Auth::Token.build(authv3_creds)
316
+ token.catalog.payload.must_equal ['catalog_data']
317
+ end
318
+
319
+ it '#get_endpoint_url' do
320
+ stub_request(:post, 'http://localhost/identity/v3/auth/tokens').
321
+ to_return(
322
+ :status => 200,
323
+ :body => JSON.dump(auth_response_v3("identity", "keystone")),
324
+ :headers => {'x-subject-token'=>'token_data'}
325
+ )
326
+
327
+ token = Fog::OpenStack::Auth::Token.build(authv3_creds)
328
+ token.catalog.get_endpoint_url(%w[identity], 'public', 'regionOne').must_equal 'http://localhost'
329
+ end
330
+ end
331
+ end
332
+
333
+ describe 'V2' do
334
+ describe '#new' do
335
+ it 'fails when missing credentials' do
336
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
337
+ to_return(:status => 200, :body => "{\"access\":{\"token\":{\"id\":\"token_data\"}}}", :headers => {})
338
+
339
+ proc do
340
+ Fog::OpenStack::Auth::Token.build({})
341
+ end.must_raise Fog::OpenStack::Auth::Token::URLError
342
+ end
343
+
344
+ describe 'using the password method' do
345
+ it 'authenticates using the tenant name' do
346
+ auth = {
347
+ :openstack_auth_url => 'http://localhost/identity',
348
+ :openstack_username => 'user',
349
+ :openstack_api_key => 'secret',
350
+ :openstack_tenant => 'tenant',
351
+ }
352
+
353
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
354
+ with(:body => "{\"auth\":{\"passwordCredentials\":{\"username\":\"user\",\"password\":\"secret\"},\
355
+ \"tenantName\":\"tenant\"}}").
356
+ to_return(:status => 200, :body => JSON.dump(auth_response_v2('identity', 'keystone')), :headers => {})
357
+
358
+ token = Fog::OpenStack::Auth::Token.build(auth)
359
+ token.get.must_equal '4ae647d3a5294690a3c29bc658e17e26'
360
+ end
361
+
362
+ it 'authenticates using the tenant id' do
363
+ auth = {
364
+ :openstack_auth_url => 'http://localhost/identity',
365
+ :openstack_username => 'user',
366
+ :openstack_api_key => 'secret',
367
+ :openstack_tenant_id => 'tenant_id',
368
+ }
369
+
370
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
371
+ with(:body => "{\"auth\":{\"passwordCredentials\":{\"username\":\"user\",\"password\":\"secret\"},\
372
+ \"tenantId\":\"tenant_id\"}}").
373
+ to_return(:status => 200, :body => JSON.dump(auth_response_v2('identity', 'keystone')), :headers => {})
374
+
375
+ token = Fog::OpenStack::Auth::Token.build(auth)
376
+ token.get.must_equal '4ae647d3a5294690a3c29bc658e17e26'
377
+ end
378
+ end
379
+
380
+ describe 'using the token method' do
381
+ it 'authenticates using the tenant name' do
382
+ auth = {
383
+ :openstack_auth_url => 'http://localhost/identity',
384
+ :openstack_auth_token => 'token_id',
385
+ :openstack_tenant => 'tenant',
386
+ }
387
+
388
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
389
+ with(:body => "{\"auth\":{\"token\":{\"id\":\"token_id\"},\"tenantName\":\"tenant\"}}").
390
+ to_return(:status => 200, :body => JSON.dump(auth_response_v2('identity', 'keystone')), :headers => {})
391
+
392
+ token = Fog::OpenStack::Auth::Token.build(auth)
393
+ token.get.must_equal '4ae647d3a5294690a3c29bc658e17e26'
394
+ end
395
+
396
+ it 'authenticates using the tenant id' do
397
+ auth = {
398
+ :openstack_auth_url => 'http://localhost/identity',
399
+ :openstack_auth_token => 'token_id',
400
+ :openstack_tenant_id => 'tenant_id',
401
+ }
402
+
403
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
404
+ with(:body => "{\"auth\":{\"token\":{\"id\":\"token_id\"},\"tenantId\":\"tenant_id\"}}").
405
+ to_return(:status => 200, :body => JSON.dump(auth_response_v2('identity', 'keystone')), :headers => {})
406
+
407
+ Fog::OpenStack::Auth::Token.build(auth)
408
+ end
409
+ end
410
+ end
411
+
412
+ describe 'when authenticated' do
413
+ let(:authv2_creds) do
414
+ {
415
+ :openstack_auth_url => 'http://localhost/identity',
416
+ :openstack_username => 'admin',
417
+ :openstack_api_key => 'secret',
418
+ :openstack_tenant => 'admin'
419
+ }
420
+ end
421
+
422
+ describe '#get' do
423
+ it 'when token has not expired' do
424
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
425
+ to_return(
426
+ :status => 200,
427
+ :body => "{\"access\":{\"token\":{\"id\":\"token_not_expired\"},\"serviceCatalog\":\
428
+ [\"catalog_data\"]}}",
429
+ :headers => {}
430
+ )
431
+
432
+ token = Fog::OpenStack::Auth::Token.build(authv2_creds)
433
+ token.stub :expired?, false do
434
+ token.get.must_equal 'token_not_expired'
435
+ end
436
+ end
437
+
438
+ it 'when token has expired' do
439
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
440
+ to_return(
441
+ :status => 200,
442
+ :body => "{\"access\":{\"token\":{\"id\":\"token_expired\"},\"serviceCatalog\":[\"catalog_data\"]}}",
443
+ :headers => {}
444
+ )
445
+
446
+ token = Fog::OpenStack::Auth::Token.build(authv2_creds)
447
+ token.stub :expired?, true do
448
+ token.get.must_equal 'token_expired'
449
+ end
450
+ end
451
+ end
452
+
453
+ it '#catalog' do
454
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
455
+ to_return(
456
+ :status => 200,
457
+ :body => "{\"access\":{\"token\":{\"id\":\"token_data\"},\"serviceCatalog\":[\"catalog_data\"]}}",
458
+ :headers => {}
459
+ )
460
+
461
+ token = Fog::OpenStack::Auth::Token.build(authv2_creds)
462
+ token.catalog.payload.must_equal ['catalog_data']
463
+ end
464
+
465
+ it '#get_endpoint_url' do
466
+ stub_request(:post, 'http://localhost/identity/v2.0/tokens').
467
+ to_return(
468
+ :status => 200,
469
+ :body => JSON.dump(auth_response_v2('identity', 'keystone')),
470
+ :headers => {'x-subject-token'=>'token_data'}
471
+ )
472
+
473
+ token = Fog::OpenStack::Auth::Token.build(authv2_creds)
474
+ token.catalog.get_endpoint_url(%w[identity], 'public', 'regionOne').must_equal 'http://localhost'
475
+ end
476
+ end
477
+ end
478
+ end