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
@@ -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