scooter 0.0.0 → 3.2.19
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.
- checksums.yaml +15 -0
- data/.env +5 -0
- data/.gitignore +47 -19
- data/Gemfile +3 -0
- data/HISTORY.md +1539 -0
- data/README.md +69 -10
- data/Rakefile +7 -0
- data/docs/http_dispatchers.md +79 -0
- data/lib/scooter.rb +11 -3
- data/lib/scooter/httpdispatchers.rb +12 -0
- data/lib/scooter/httpdispatchers/activity.rb +46 -0
- data/lib/scooter/httpdispatchers/activity/v1/v1.rb +50 -0
- data/lib/scooter/httpdispatchers/classifier.rb +376 -0
- data/lib/scooter/httpdispatchers/classifier/v1/v1.rb +99 -0
- data/lib/scooter/httpdispatchers/code_manager.rb +31 -0
- data/lib/scooter/httpdispatchers/code_manager/v1/v1.rb +17 -0
- data/lib/scooter/httpdispatchers/consoledispatcher.rb +132 -0
- data/lib/scooter/httpdispatchers/httpdispatcher.rb +168 -0
- data/lib/scooter/httpdispatchers/orchestrator/v1/v1.rb +87 -0
- data/lib/scooter/httpdispatchers/orchestratordispatcher.rb +83 -0
- data/lib/scooter/httpdispatchers/puppetdb/v4/v4.rb +51 -0
- data/lib/scooter/httpdispatchers/puppetdbdispatcher.rb +390 -0
- data/lib/scooter/httpdispatchers/rbac.rb +231 -0
- data/lib/scooter/httpdispatchers/rbac/v1/directory_service.rb +68 -0
- data/lib/scooter/httpdispatchers/rbac/v1/v1.rb +116 -0
- data/lib/scooter/ldap.rb +349 -0
- data/lib/scooter/ldap/ldap_fixtures.rb +60 -0
- data/lib/scooter/middleware/rbac_auth_token.rb +35 -0
- data/lib/scooter/utilities.rb +9 -0
- data/lib/scooter/utilities/beaker_utilities.rb +41 -0
- data/lib/scooter/utilities/string_utilities.rb +32 -0
- data/lib/scooter/version.rb +3 -1
- data/scooter.gemspec +23 -6
- data/spec/scooter/beaker_utilities_spec.rb +53 -0
- data/spec/scooter/httpdispatchers/activity/activity_spec.rb +218 -0
- data/spec/scooter/httpdispatchers/classifier/classifier_spec.rb +542 -0
- data/spec/scooter/httpdispatchers/code_manager/code-manager_spec.rb +67 -0
- data/spec/scooter/httpdispatchers/consoledispatcher_spec.rb +80 -0
- data/spec/scooter/httpdispatchers/httpdispatcher_spec.rb +91 -0
- data/spec/scooter/httpdispatchers/middleware/rbac_auth_token_spec.rb +58 -0
- data/spec/scooter/httpdispatchers/orchestratordispatcher_spec.rb +195 -0
- data/spec/scooter/httpdispatchers/puppetdbdispatcher_spec.rb +246 -0
- data/spec/scooter/httpdispatchers/rbac/rbac_spec.rb +387 -0
- data/spec/scooter/string_utilities_spec.rb +83 -0
- data/spec/spec_helper.rb +8 -0
- metadata +270 -18
- data/LICENSE.txt +0 -15
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
module Scooter
|
|
3
|
+
|
|
4
|
+
describe HttpDispatchers::PuppetdbDispatcher do
|
|
5
|
+
|
|
6
|
+
let(:host) { double('host') }
|
|
7
|
+
let(:credentials) { double('credentials') }
|
|
8
|
+
let(:credentials) { { login: 'Ziggy', password: 'Stardust' } }
|
|
9
|
+
|
|
10
|
+
subject { HttpDispatchers::PuppetdbDispatcher.new(host) }
|
|
11
|
+
|
|
12
|
+
unixhost = { roles: ['test_role'],
|
|
13
|
+
'platform' => 'debian-7-x86_64' }
|
|
14
|
+
let(:host) { Beaker::Host.create('test.com', unixhost, {}) }
|
|
15
|
+
|
|
16
|
+
before do
|
|
17
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:pe_ca_cert_file).and_return('cert file')
|
|
18
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:pe_private_key).and_return('key file')
|
|
19
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:pe_hostcert).and_return('host cert')
|
|
20
|
+
expect(OpenSSL::PKey).to receive(:read).and_return('Pkey')
|
|
21
|
+
expect(OpenSSL::X509::Certificate).to receive(:new).and_return('client_cert')
|
|
22
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:get_public_ip).and_return('public_ip')
|
|
23
|
+
expect(subject).not_to be_nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'with a beaker host passed in' do
|
|
27
|
+
describe '.query_nodes' do
|
|
28
|
+
before do
|
|
29
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
30
|
+
# and replace it with the Test adapter
|
|
31
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
32
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
33
|
+
stub.post('/pdb/query/v4/nodes') { [200, []] }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
it 'query for all nodes' do
|
|
37
|
+
expect { subject.query_nodes }.not_to raise_error
|
|
38
|
+
expect(subject.query_nodes.status).to eq(200)
|
|
39
|
+
end
|
|
40
|
+
it 'query for nodes matching query' do
|
|
41
|
+
expect { subject.query_nodes('["and", ["=", ["fact", "kernel"], "Linux"]]') }.not_to raise_error
|
|
42
|
+
response = subject.query_nodes('["and", ["=", ["fact", "kernel"], "Linux"]]')
|
|
43
|
+
expect(response.status).to eq(200)
|
|
44
|
+
hashed_query = CGI.parse(response.env.url.query)
|
|
45
|
+
expect(hashed_query).to eq('query' => ['["and", ["=", ["fact", "kernel"], "Linux"]]'])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe '.query_catalogs' do
|
|
50
|
+
before do
|
|
51
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
52
|
+
# and replace it with the Test adapter
|
|
53
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
54
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
55
|
+
stub.post('/pdb/query/v4/catalogs') { [200, []] }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
it 'query for all catalogs' do
|
|
59
|
+
expect { subject.query_catalogs }.not_to raise_error
|
|
60
|
+
expect(subject.query_catalogs.status).to eq(200)
|
|
61
|
+
end
|
|
62
|
+
it 'query for catalogs matching query' do
|
|
63
|
+
expect { subject.query_catalogs('[">","producer_timestamp","2015-11-19"]') }.not_to raise_error
|
|
64
|
+
response = subject.query_catalogs('[">","producer_timestamp","2015-11-19"]')
|
|
65
|
+
expect(response.status).to eq(200)
|
|
66
|
+
hashed_query = CGI.parse(response.env.url.query)
|
|
67
|
+
expect(hashed_query).to eq('query' => ['[">","producer_timestamp","2015-11-19"]'])
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe '.query_reports' do
|
|
72
|
+
before do
|
|
73
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
74
|
+
# and replace it with the Test adapter
|
|
75
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
76
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
77
|
+
stub.post('/pdb/query/v4/reports') { [200, []] }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
it 'query for all reports' do
|
|
81
|
+
expect { subject.query_reports }.not_to raise_error
|
|
82
|
+
expect(subject.query_reports.status).to eq(200)
|
|
83
|
+
end
|
|
84
|
+
it 'query for reports matching query' do
|
|
85
|
+
expect { subject.query_reports('["extract",[["function","count"], "status"], ["~","certname",""], ["group_by", "status"]]') }.not_to raise_error
|
|
86
|
+
response = subject.query_reports('["extract",[["function","count"], "status"], ["~","certname",""], ["group_by", "status"]]')
|
|
87
|
+
expect(response.status).to eq(200)
|
|
88
|
+
hashed_query = CGI.parse(response.env.url.query)
|
|
89
|
+
expect(hashed_query).to eq('query' => ['["extract",[["function","count"], "status"], ["~","certname",""], ["group_by", "status"]]'])
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe '.query_facts' do
|
|
94
|
+
before do
|
|
95
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
96
|
+
# and replace it with the Test adapter
|
|
97
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
98
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
99
|
+
stub.post('/pdb/query/v4/facts') { [200, []] }
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
it 'query for all facts' do
|
|
103
|
+
expect { subject.query_facts }.not_to raise_error
|
|
104
|
+
expect(subject.query_facts.status).to eq(200)
|
|
105
|
+
end
|
|
106
|
+
it 'query for facts matching query' do
|
|
107
|
+
expect { subject.query_facts('["=", "name", "operatingsystem"]') }.not_to raise_error
|
|
108
|
+
response = subject.query_facts('["=", "name", "operatingsystem"]')
|
|
109
|
+
expect(response.status).to eq(200)
|
|
110
|
+
hashed_query = CGI.parse(response.env.url.query)
|
|
111
|
+
expect(hashed_query).to eq('query' => ['["=", "name", "operatingsystem"]'])
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# N.B. in several tests below we use ++subject.send(:foo?)++ instead of ++subject.foo?++ because
|
|
116
|
+
# ++foo++ is a private method, so we have to use this sneaky workaround to access the methods for
|
|
117
|
+
# testing purposes. Ruby bug or Ruby feature? -- you decide.
|
|
118
|
+
|
|
119
|
+
describe '.nodes_match?' do
|
|
120
|
+
before do
|
|
121
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
122
|
+
# and replace it with the Test adapter
|
|
123
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
124
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
125
|
+
stub.post('/pdb/query/v4/nodes') { [200, [], [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' }]] }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
it 'nodes different size' do
|
|
129
|
+
expect(subject.send(:nodes_match?, [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' },
|
|
130
|
+
{ 'certname' => 'name2', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' }])).to be false
|
|
131
|
+
end
|
|
132
|
+
it 'nodes do not match' do
|
|
133
|
+
# N.B.: nodes are considered to match even if facts_timestamp and/or catalog_timestamp differ
|
|
134
|
+
expect(subject.send(:nodes_match?, [{ 'certname' => 'name_bad', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' }])).to be false
|
|
135
|
+
expect(subject.send(:nodes_match?, [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time_bad', 'catalog_timestamp' => 'catalog_time' }])).to be false
|
|
136
|
+
end
|
|
137
|
+
it 'nodes match' do
|
|
138
|
+
# N.B.: nodes are considered to match even if facts_timestamp and/or catalog_timestamp differ
|
|
139
|
+
expect(subject.send(:nodes_match?, [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' }])).to be true
|
|
140
|
+
expect(subject.send(:nodes_match?, [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time_bad', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' }])).to be true
|
|
141
|
+
expect(subject.send(:nodes_match?, [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time_bad' }])).to be true
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe '.catalogs_match?' do
|
|
147
|
+
before do
|
|
148
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
149
|
+
# and replace it with the Test adapter
|
|
150
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
151
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
152
|
+
stub.post('/pdb/query/v4/catalogs') { [200, [], [{ 'catalog_uuid' => 'catalog_uuid_1', 'producer_timestamp' => 'time' }]] }
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
it 'catalogs different size' do
|
|
156
|
+
expect(subject.send(:catalogs_match?, [{ 'catalog_uuid' => 'catalog_uuid_1', 'producer_timestamp' => 'time' },
|
|
157
|
+
{ 'catalog_uuid' => 'catalog_uuid_2', 'producer_timestamp' => 'time2' }])).to be false
|
|
158
|
+
end
|
|
159
|
+
it 'catalogs do not match' do
|
|
160
|
+
expect(subject.send(:catalogs_match?, [{ 'catalog_uuid' => 'catalog_uuid_2', 'producer_timestamp' => 'time2' }])).to be false
|
|
161
|
+
end
|
|
162
|
+
it 'catalogs match' do
|
|
163
|
+
expect(subject.send(:catalogs_match?, [{ 'catalog_uuid' => 'catalog_uuid_1', 'producer_timestamp' => 'time' }])).to be true
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe '.facts_match?' do
|
|
169
|
+
before do
|
|
170
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
171
|
+
# and replace it with the Test adapter
|
|
172
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
173
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
174
|
+
stub.post('/pdb/query/v4/facts') { [200, [], [{ 'name' => 'name', 'value' => 'value' }]] }
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
it 'facts different size' do
|
|
178
|
+
expect(subject.send(:facts_match?, [{ 'name' => 'name', 'value' => 'value' },
|
|
179
|
+
{ 'name2' => 'name', 'value2' => 'value' }])).to be false
|
|
180
|
+
end
|
|
181
|
+
it 'facts do not match' do
|
|
182
|
+
expect(subject.send(:facts_match?, [{ 'name2' => 'name', 'value2' => 'value' }])).to be false
|
|
183
|
+
end
|
|
184
|
+
it 'facts match' do
|
|
185
|
+
expect(subject.send(:facts_match?, [{ 'name' => 'name', 'value' => 'value' }])).to be true
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
describe '.reports_match?' do
|
|
191
|
+
before do
|
|
192
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
193
|
+
# and replace it with the Test adapter
|
|
194
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
195
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
196
|
+
stub.post('/pdb/query/v4/reports') { [200, [], [{ 'hash' => 'hash_value', 'producer_timestamp' => 'time' }]] }
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
it 'reports different size' do
|
|
200
|
+
expect(subject.send(:reports_match?, [{ 'hash' => 'hash_value', 'producer_timestamp' => 'time' },
|
|
201
|
+
{ 'hash' => 'hash_value2', 'producer_timestamp' => 'time2' }])).to be false
|
|
202
|
+
end
|
|
203
|
+
it 'reports do not match' do
|
|
204
|
+
expect(subject.send(:reports_match?, [{ 'hash' => 'hash_value2', 'producer_timestamp' => 'time2' }])).to be false
|
|
205
|
+
end
|
|
206
|
+
it 'reports match' do
|
|
207
|
+
expect(subject.send(:reports_match?, [{ 'hash' => 'hash_value', 'producer_timestamp' => 'time' }])).to be true
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
describe '.database_matches_self?' do
|
|
213
|
+
before do
|
|
214
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
215
|
+
# and replace it with the Test adapter
|
|
216
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
217
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
218
|
+
stub.post('/pdb/query/v4/nodes') { |env| env[:url].to_s == "https://test.com:8081/pdb/query/v4/nodes" ?
|
|
219
|
+
[200, [], [{ 'certname' => 'name', 'facts_timestamp' => 'facts_time', 'report_timestamp' => 'reports_time', 'catalog_timestamp' => 'catalog_time' }]] :
|
|
220
|
+
[200, [], [{ 'certname' => 'name2', 'facts_timestamp' => 'facts_time', 'report_timestamp2' => 'reports_time', 'catalog_timestamp' => 'catalog_time2' }]] }
|
|
221
|
+
stub.post('/pdb/query/v4/catalogs') { |env| env[:url].to_s == "https://test.com:8081/pdb/query/v4/catalogs" ?
|
|
222
|
+
[200, [], [{ 'catalog_uuid' => 'catalog_uuid_1', 'producer_timestamp' => 'time' }]] :
|
|
223
|
+
[200, [], [{ 'catalog_uuid' => 'catalog_uuid_2', 'producer_timestamp' => 'time2' }]] }
|
|
224
|
+
stub.post('/pdb/query/v4/facts') { |env| env[:url].to_s == "https://test.com:8081/pdb/query/v4/facts" ?
|
|
225
|
+
[200, [], [{ 'name' => 'name', 'value' => 'value' }]] :
|
|
226
|
+
[200, [], [{ 'name' => 'name2', 'value' => 'value2' }]] }
|
|
227
|
+
stub.post('/pdb/query/v4/reports') { |env| env[:url].to_s == "https://test.com:8081/pdb/query/v4/reports" ?
|
|
228
|
+
[200, [], [{ 'hash' => 'hash_value', 'producer_timestamp' => 'time' }]] :
|
|
229
|
+
[200, [], [{ 'hash' => 'hash_value2', 'producer_timestamp' => 'time2' }]] }
|
|
230
|
+
end
|
|
231
|
+
expect(subject).to receive(:create_default_connection).with(any_args).twice.and_return(subject.connection)
|
|
232
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:get_public_ip).and_return('public_ip')
|
|
233
|
+
end
|
|
234
|
+
it 'compare with self' do
|
|
235
|
+
expect(subject.database_matches_self?('test.com')).to be_truthy
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it 'compare with different' do
|
|
239
|
+
expect(subject.faraday_logger).to receive(:warn).with /Nodes do not match/
|
|
240
|
+
expect(subject.database_matches_self?('test2.com')).to be_falsey
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Scooter
|
|
4
|
+
|
|
5
|
+
describe Scooter::HttpDispatchers::Rbac do
|
|
6
|
+
|
|
7
|
+
let(:host) { double('host') }
|
|
8
|
+
let(:credentials) { double('credentials') }
|
|
9
|
+
let(:user_list) {
|
|
10
|
+
[
|
|
11
|
+
{
|
|
12
|
+
:email => "",
|
|
13
|
+
:is_revoked => false,
|
|
14
|
+
:last_login => nil,
|
|
15
|
+
:is_remote => false,
|
|
16
|
+
:login => "api_user",
|
|
17
|
+
:is_superuser => true,
|
|
18
|
+
:id => "af94921f-bd76-4b58-b5ce-e17c029a2790",
|
|
19
|
+
:role_ids => [
|
|
20
|
+
1
|
|
21
|
+
],
|
|
22
|
+
:display_name => "API User",
|
|
23
|
+
:is_group => false
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
:email => "",
|
|
27
|
+
:is_revoked => false,
|
|
28
|
+
:last_login => "2016-06-09T19 =>14 =>25.923Z",
|
|
29
|
+
:is_remote => false,
|
|
30
|
+
:login => "admin",
|
|
31
|
+
:is_superuser => true,
|
|
32
|
+
:id => "42bf351c-f9ec-40af-84ad-e976fec7f4bd",
|
|
33
|
+
:role_ids => [
|
|
34
|
+
1
|
|
35
|
+
],
|
|
36
|
+
:display_name => "Administrator",
|
|
37
|
+
:is_group => false
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
let(:role_list) {
|
|
42
|
+
[
|
|
43
|
+
{
|
|
44
|
+
:description => "Manage users and their permissions, and create and modify node groups and other objects.",
|
|
45
|
+
:user_ids => [
|
|
46
|
+
"42bf351c-f9ec-40af-84ad-e976fec7f4bd",
|
|
47
|
+
"af94921f-bd76-4b58-b5ce-e17c029a2790"
|
|
48
|
+
],
|
|
49
|
+
:group_ids => [],
|
|
50
|
+
:display_name => "Administrators",
|
|
51
|
+
:id => 1,
|
|
52
|
+
:permissions => [
|
|
53
|
+
{
|
|
54
|
+
:object_type => "console_page",
|
|
55
|
+
:action => "view",
|
|
56
|
+
:instance => "*"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
:object_type => "node_groups",
|
|
60
|
+
:action => "modify_children",
|
|
61
|
+
:instance => "*"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
:object_type => "puppet_agent",
|
|
65
|
+
:action => "run",
|
|
66
|
+
:instance => "*"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
:object_type => "users",
|
|
70
|
+
:action => "edit",
|
|
71
|
+
:instance => "*"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
:object_type => "roles",
|
|
75
|
+
:action => "edit",
|
|
76
|
+
:instance => "*"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
:object_type => "users",
|
|
80
|
+
:action => "create",
|
|
81
|
+
:instance => "*"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
:object_type => "node_groups",
|
|
85
|
+
:action => "set_environment",
|
|
86
|
+
:instance => "*"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
:object_type => "user_groups",
|
|
90
|
+
:action => "import",
|
|
91
|
+
:instance => "*"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
:object_type => "roles",
|
|
95
|
+
:action => "create",
|
|
96
|
+
:instance => "*"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
:object_type => "users",
|
|
100
|
+
:action => "reset_password",
|
|
101
|
+
:instance => "*"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
:object_type => "directory_service",
|
|
105
|
+
:action => "edit",
|
|
106
|
+
:instance => "*"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
:object_type => "cert_requests",
|
|
110
|
+
:action => "accept_reject",
|
|
111
|
+
:instance => "*"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
:object_type => "roles",
|
|
115
|
+
:action => "edit_members",
|
|
116
|
+
:instance => "*"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
:object_type => "node_groups",
|
|
120
|
+
:action => "edit_classification",
|
|
121
|
+
:instance => "*"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
:object_type => "users",
|
|
125
|
+
:action => "disable",
|
|
126
|
+
:instance => "*"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
:object_type => "tokens",
|
|
130
|
+
:action => "override_lifetime",
|
|
131
|
+
:instance => "*"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
:object_type => "nodes",
|
|
135
|
+
:action => "view_data",
|
|
136
|
+
:instance => "*"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
:object_type => "environment",
|
|
140
|
+
:action => "deploy_code",
|
|
141
|
+
:instance => "*"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
:object_type => "nodes",
|
|
145
|
+
:action => "edit_data",
|
|
146
|
+
:instance => "*"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
:object_type => "node_groups",
|
|
150
|
+
:action => "edit_child_rules",
|
|
151
|
+
:instance => "*"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
:object_type => "orchestration",
|
|
155
|
+
:action => "use",
|
|
156
|
+
:instance => "*"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
:object_type => "user_groups",
|
|
160
|
+
:action => "delete",
|
|
161
|
+
:instance => "*"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
:object_type => "node_groups",
|
|
165
|
+
:action => "view",
|
|
166
|
+
:instance => "*"
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
:description => "Create and modify node groups and other objects.",
|
|
172
|
+
:user_ids => [],
|
|
173
|
+
:group_ids => [],
|
|
174
|
+
:display_name => "Operators",
|
|
175
|
+
:id => 2,
|
|
176
|
+
:permissions => [
|
|
177
|
+
{
|
|
178
|
+
:object_type => "tokens",
|
|
179
|
+
:action => "override_lifetime",
|
|
180
|
+
:instance => "*"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
:object_type => "cert_requests",
|
|
184
|
+
:action => "accept_reject",
|
|
185
|
+
:instance => "*"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
:object_type => "node_groups",
|
|
189
|
+
:action => "view",
|
|
190
|
+
:instance => "*"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
:object_type => "node_groups",
|
|
194
|
+
:action => "edit_classification",
|
|
195
|
+
:instance => "*"
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
:object_type => "node_groups",
|
|
199
|
+
:action => "modify_children",
|
|
200
|
+
:instance => "*"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
:object_type => "puppet_agent",
|
|
204
|
+
:action => "run",
|
|
205
|
+
:instance => "*"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
:object_type => "environment",
|
|
209
|
+
:action => "deploy_code",
|
|
210
|
+
:instance => "*"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
:object_type => "node_groups",
|
|
214
|
+
:action => "set_environment",
|
|
215
|
+
:instance => "*"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
:object_type => "orchestration",
|
|
219
|
+
:action => "use",
|
|
220
|
+
:instance => "*"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
:object_type => "console_page",
|
|
224
|
+
:action => "view",
|
|
225
|
+
:instance => "*"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
:object_type => "node_groups",
|
|
229
|
+
:action => "edit_child_rules",
|
|
230
|
+
:instance => "*"
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
:description => "Test delete role functionality",
|
|
236
|
+
:user_ids => [],
|
|
237
|
+
:group_ids => [],
|
|
238
|
+
:display_name => "Dummy role",
|
|
239
|
+
:id => 13,
|
|
240
|
+
:permissions => [
|
|
241
|
+
{
|
|
242
|
+
:object_type => "console_page",
|
|
243
|
+
:action => "view",
|
|
244
|
+
:instance => "*"
|
|
245
|
+
}]
|
|
246
|
+
}
|
|
247
|
+
]
|
|
248
|
+
}
|
|
249
|
+
let(:group_list) {
|
|
250
|
+
[]
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
subject { HttpDispatchers::ConsoleDispatcher.new(host, credentials) }
|
|
254
|
+
|
|
255
|
+
context 'with a beaker host passed in' do
|
|
256
|
+
|
|
257
|
+
unixhost = { roles: ['test_role'],
|
|
258
|
+
'platform' => 'debian-7-x86_64' }
|
|
259
|
+
let(:host) { Beaker::Host.create('test.com', unixhost, {}) }
|
|
260
|
+
let(:credentials) { { login: 'Ziggy', password: 'Stardust' } }
|
|
261
|
+
|
|
262
|
+
before do
|
|
263
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:pe_ca_cert_file).and_return('cert file')
|
|
264
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:get_public_ip).and_return('public_ip')
|
|
265
|
+
expect(subject).not_to be_nil
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
describe '.acquire_token_with_credentials' do
|
|
269
|
+
before do
|
|
270
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
271
|
+
# and replace it with the Test adapter
|
|
272
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
273
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
274
|
+
stub.post('/rbac-api/v1/auth/token') { [200, {}, 'token' => 'blah'] }
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
it 'sets the token instance variable for the dispatcher' do
|
|
278
|
+
expect { subject.acquire_token_with_credentials }.not_to raise_error
|
|
279
|
+
expect(subject.token).to eq('blah')
|
|
280
|
+
end
|
|
281
|
+
it 'accepts an optional lifetime parameter' do
|
|
282
|
+
expect { subject.acquire_token_with_credentials('600') }.not_to raise_error
|
|
283
|
+
expect(subject.token).to eq('blah')
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
describe 'ensure failure to get a token does not set the token instance variable' do
|
|
288
|
+
before do
|
|
289
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
290
|
+
# and replace it with the Test adapter
|
|
291
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
292
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
293
|
+
stub.post('/rbac-api/v1/auth/token') { [401, {}, 'unauthorized'] }
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
it 'the token variable should still be nil for a failed request' do
|
|
297
|
+
expect { subject.acquire_token_with_credentials }.to raise_error(Faraday::ClientError)
|
|
298
|
+
expect(subject.token).to eq(nil)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
describe '.delete_role_by_name' do
|
|
303
|
+
before do
|
|
304
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
305
|
+
# and replace it with the Test adapter
|
|
306
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
307
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
308
|
+
stub.get('rbac-api/v1/roles') { [200, {}, role_list] }
|
|
309
|
+
stub.delete('rbac-api/v1/roles/') { [200, {}] }
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
it 'returns 200 when deleting role' do
|
|
313
|
+
response = subject.delete_role_by_name('Dummy role')
|
|
314
|
+
expect(response.status).to eq(200)
|
|
315
|
+
end
|
|
316
|
+
it 'returns 400 when getting deleted role' do
|
|
317
|
+
response = subject.get_role_by_name('Dummy role')
|
|
318
|
+
expect(response).to be_nil
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
describe '.get_group_data_by_name' do
|
|
323
|
+
let(:groups_array) {
|
|
324
|
+
[{ "user_ids" => [],
|
|
325
|
+
"role_ids" => [],
|
|
326
|
+
"display_name" => "",
|
|
327
|
+
"is_superuser" => false,
|
|
328
|
+
"is_remote" => true,
|
|
329
|
+
"is_group" => true,
|
|
330
|
+
"login" => "group1",
|
|
331
|
+
"id" => "09c2c1fd-ea01-4555-bc7b-a8f25c4511f8" },
|
|
332
|
+
{ "user_ids" => [],
|
|
333
|
+
"role_ids" => [],
|
|
334
|
+
"display_name" => "",
|
|
335
|
+
"is_superuser" => false,
|
|
336
|
+
"is_remote" => true,
|
|
337
|
+
"is_group" => true,
|
|
338
|
+
"login" => "group2",
|
|
339
|
+
"id" => "09c2c1fd-ea01-4555-bc7b-a8f25c4511f7" }]
|
|
340
|
+
}
|
|
341
|
+
before do
|
|
342
|
+
expect(subject).to receive(:get_list_of_groups) { groups_array }
|
|
343
|
+
end
|
|
344
|
+
it 'can find group1 in the payload' do
|
|
345
|
+
expect(subject.get_group_data_by_name('group1')).to eq(groups_array[0])
|
|
346
|
+
end
|
|
347
|
+
it 'can find group2 in the payload' do
|
|
348
|
+
expect(subject.get_group_data_by_name('group2')).to eq(groups_array[1])
|
|
349
|
+
end
|
|
350
|
+
it 'returns nil for group3, who is not in the payload' do
|
|
351
|
+
expect(subject.get_group_data_by_name('group3')).to eq(nil)
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
describe '.rbac_database_matches_self' do
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
before do
|
|
359
|
+
# find the index of the default Faraday::Adapter::NetHttp handler
|
|
360
|
+
# and replace it with the Test adapter
|
|
361
|
+
index = subject.connection.builder.handlers.index(Faraday::Adapter::NetHttp)
|
|
362
|
+
subject.connection.builder.swap(index, Faraday::Adapter::Test) do |stub|
|
|
363
|
+
stub.get('rbac-api/v1/users') { |env| env[:url].to_s == "https://test.com:4433/rbac-api/v1/users" ?
|
|
364
|
+
[200, [], user_list] :
|
|
365
|
+
[200, [], user_list.dup.push('another_array_item')] }
|
|
366
|
+
stub.get('rbac-api/v1/groups') { |env| env[:url].to_s == "https://test.com:4433/rbac-api/v1/groups" ?
|
|
367
|
+
[200, [], group_list] :
|
|
368
|
+
[200, [], group_list.dup.push('another_array_item')] }
|
|
369
|
+
stub.get('rbac-api/v1/roles') { |env| env[:url].to_s == "https://test.com:4433/rbac-api/v1/roles" ?
|
|
370
|
+
[200, [], role_list] :
|
|
371
|
+
[200, [], role_list.dup.push('another_array_item')] }
|
|
372
|
+
end
|
|
373
|
+
expect(subject).to receive(:create_default_connection).with(any_args).twice.and_return(subject.connection)
|
|
374
|
+
expect(Scooter::Utilities::BeakerUtilities).to receive(:get_public_ip).and_return('public_ip')
|
|
375
|
+
end
|
|
376
|
+
it 'compare with self' do
|
|
377
|
+
expect(subject.rbac_database_matches_self?('test.com')).to be_truthy
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
it 'compare with different' do
|
|
381
|
+
expect(subject.faraday_logger).to receive(:warn).with /Users do not match/
|
|
382
|
+
expect(subject.rbac_database_matches_self?('test2.com')).to be_falsey
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|