forked from ManageIQ/manageiq-providers-ansible_tower
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spec_helper.rake
350 lines (292 loc) · 15.3 KB
/
spec_helper.rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
namespace :spec do
desc "Populate expected Tower objects for casssettes and spec tests"
task :populate_tower do
tower_host = ENV['TOWER_URL'] || "https://dev-ansible-tower3.example.com/api/v1/"
id = ENV['TOWER_USER'] || 'testuser'
password = ENV['TOWER_PASSWORD'] || 'secret'
PopulateTower.new(tower_host, id, password, TowerData.new(true)).create_dataset.counts
end
desc "Get counts of various Tower objects"
task :tower_counts do
tower_host = ENV['TOWER_URL'] || "https://dev-ansible-tower3.example.com/api/v1/"
id = ENV['TOWER_USER'] || 'testuser'
password = ENV['TOWER_PASSWORD'] || 'secret'
PopulateTower.new(tower_host, id, password, TowerData.new(false)).counts
end
end
class TowerData
def initialize(delete)
require ManageIQ::Providers::AnsibleTower::Engine.root.join('spec', 'support', 'tower_data_helper')
if delete || !Spec::Support::TowerDataHelper.tower_data_initialized?
init_blank
else
@data = Spec::Support::TowerDataHelper.tower_data
raise 'Invalid Tower data stored, can’t update.' unless @data.kind_of?(Hash)
end
end
def init_blank
@data = {}
write
end
def read
@data
end
def write
Spec::Support::TowerDataHelper.tower_data = @data
end
def update
yield @data if block_given?
write
@data
end
end
class PopulateTower
# This is to create a set of objects in Tower and the objects will be captured in a vcr cassette for
# refresh spec tests. If we need to update the cassette, we can update/rerun this script to modify the objects
# and so spec expectations can be updated (hopefully) easily
#
# It will print out object counts that are needed for the spec
# Sample output on console
#
# === Re-creating Tower objects ===
# deleting old spec_test_org: /api/v1/organizations/39/
# Created name=spec_test_org manager_ref/ems_ref= 40 url=/api/v1/organizations/40/
# Created name=hello_scm_cred manager_ref/ems_ref= 136 url=/api/v1/credentials/136/
# Created name=hello_machine_cred manager_ref/ems_ref= 137 url=/api/v1/credentials/137/
# Created name=hello_vault_cred manager_ref/ems_ref= 138 url=/api/v1/credentials/138/
# Created name=hello_aws_cred manager_ref/ems_ref= 139 url=/api/v1/credentials/139/
# Created name=hello_network_cred manager_ref/ems_ref= 140 url=/api/v1/credentials/140/
# Created name=hello_inventory manager_ref/ems_ref= 110 url=/api/v1/inventories/110/
# Created name=hello_vm manager_ref/ems_ref= 249 url=/api/v1/hosts/249/
# Created name=hello_repo manager_ref/ems_ref= 591 url=/api/v1/projects/591/
# deleting old hello_template: /api/v1/job_templates/589/
# Created name=hello_template manager_ref/ems_ref= 592 url=/api/v1/job_templates/592/
# deleting old hello_template_with_survey: /api/v1/job_templates/590/
# Created name=hello_template_with_survey manager_ref/ems_ref= 593 url=/api/v1/job_templates/593/
# created /api/v1/job_templates/594/ survey_spec
# Created name=another_repo manager_ref/ems_ref= 594 url=/api/v1/projects/594/
# === Object counts ===
# configuration_script (job_templates) : 120
# configuration_script_source (projects) : 32
# configured_system (hosts) : 133
# inventory_group (inventories) : 29
# credential (credentials) : 47
# configuration_script_payload (playbooks) : 139
# hello_repo : 61
#
require "faraday"
require 'faraday_middleware'
MAX_TRIES = 10
TRY_SLEEP = 2
DEL_SLEEP = 20
def initialize(tower_host, id, password, tower_data)
@conn = Faraday.new(tower_host, :ssl => {:verify => false}) do |c|
c.use(FaradayMiddleware::EncodeJson)
c.use(FaradayMiddleware::FollowRedirects, :limit => 3, :standards_compliant => true)
c.use Faraday::Response::RaiseError
c.adapter(Faraday.default_adapter)
c.basic_auth(id, password)
end
@tower_data = tower_data
uri = '/api/v1/config'
config = get_obj(uri)
@version = Gem::Version.new(config['version'])
@tower_data.update { |td| td['config'] = config.slice('version') }
uri = '/api/v1/me'
me = get_obj(uri)
@tower_data.update { |td| td['user'] = me['results'].first.slice('id') }
end
def v3_2?
@version >= Gem::Version.new('3.2')
end
def create_obj(uri, data, dumped_fields = %w())
del_obj(uri, data['name'])
obj = JSON.parse(@conn.post(uri, data).body)
puts "%s %s %s" % ["Created name=#{obj['name']}".ljust(40), "manager_ref/ems_ref= #{obj['id']}".ljust(30), "url=#{obj['url']}".ljust(10)]
dumped_data = obj.slice(*dumped_fields)
@tower_data.update { |td| td['items'][obj['name']] = dumped_data } unless dumped_data.empty?
obj
end
def del_obj(uri, match_name)
obj = get_obj(uri)
obj['results'].each do |item|
next if item['name'] != match_name
puts " deleting old #{item['name']}: #{item['url']}"
resp = @conn.delete(item['url'])
sleep(DEL_SLEEP) # without sleep, sometimes subsequent create will return 400. Seems the deletion has some delay in Tower
resp
end
del_obj(obj['next'], match_name) if obj['next']
end
def get_obj(uri)
JSON.parse(@conn.get(uri).body)
end
def try_get_obj_until(uri)
current_try = 1
loop do
raise "Requested operation did not finish even after #{current_try} tries." if current_try > MAX_TRIES
obj = get_obj(uri)
return obj if yield obj
current_try = current_try.succ
sleep(TRY_SLEEP)
end
end
def create_dataset
ssh_key_data = <<~HEREDOC
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEArIIYuT+hC2dhPaSx68zTxsh5OJ3byVLNoX7urk8XU20OjlK4
7++J7qqkHojXadRZrJI69/BFteqOpLr16fAuTdPnEV1dIolEApT9Gd5sEMb4SFFc
QmZPtOCuFMRjweQBVqAFboUDpzp1Yosjyiw34JWaT8n2SVYjgFB/6SZt9/r/ZHjU
qOnQi/VY1Zp6eWtjW+LpverzCDS7EAv06OLeu9CZtKLNl8DcgcCvCbuONPCsbaSv
FtK8kw4Ev/oJvoYa3RbMphx9dfj8WB0xOcdlDmJLlvqw/iuBX0Ktslm/nADcPcxK
sd37i8Ds2BRVIlr7F3Pblh77TIP+KWzM0lVs1wIDAQABAoIBAAdpj6ZmFYVn68W6
TerT4kWoV40XO1prNGq8CYVz4Iy1Iur6ovesU0DuFB87wgXKGhBQODhvGo+2hGqP
ngFvUI4HjOYyHM5fF40E2dtCs2IFKqXw2QYBX2tmPBSoW6D5KxWNyq31CTMmT+Ts
FZ2aSMxdoUPMaci86smYq+ZYwGDnVfp2Da5G/GnvdmN+x51mMku5hETBMCOpR+n9
Z4bYnayVGyLXBJvwhx3pdIprwzAvoiySFjp/tFk+knxiPK84dJ3tIfdtgXmf1Cp9
pEqDQR3lnvwW0LrBG3c6MiJRlp+Pl3EOZNMLdmsaKODnInwO2U5BNPQuVHPdrObD
1GXxcAECgYEA3xkFdbQ+I6QZH5OSNxPKRPcqcYuYewTwQKmiL3mSoICfV9dRNV3e
ewQpcca7h9dcjTtdyx8PfvCNFR/uh/FhMw+kRXb4bdKDbDrKcQ9x23RFatbsgN14
q90a6FaEOjOXf0TiTNqP/LTFry1x2r1ZCDLtVcg5zWM/iwUgrO5qOJkCgYEAxfMV
ijLKtBg8Mbdhb2F29vIxMokZS++AhEjWuWl7d/DCApjCXzrfMaHnBC6b4Oppubkp
i40KnkaaDSy03U4hpcSPoPONbv2Fw4o/88ml71DF44D7kXCIFjSMvPLEtU2qLl4z
o4dHUSbtycBzn+wou+IdgPNqNnBYvl/eBNHvBu8CgYBQJ3M4uMtijsCgAasUsr2H
Ta4oIVllSX7wHIIywGEX3V5idu+sVs9qLzKcuCQESDHuZBfstHoix1ZI8rIGkYi0
ibghZP8Ypful1PGK8Vuc1wdhvVo3alrClKvoMb1ME+EoTp1ns1bsGh60M4Wma0Uj
lviCS2/JBRF9Zxg4SWhMcQKBgQC3PLABv8a4M371HqXJLtWq/sLf3t1V15yF1888
zxIGEw3kzXeQI7UcAp0Q1/xflV7NF0QH9EWSAhT0gR/jhEHNa0jxWsLfrTs3qTBO
AanjAEhOssUs+phexcJJ3giNNBmG1pjClaVEz95qVgYyUa/bTBK3nZwCTLk5cRDa
MWMsbQKBgCaNkKxH/gZBxVGbnjxbaxTGGq2TxNrKcKWEY4aIybcJ1kM0+UctHPy2
ixDk3cLUN9/a24A9BI+3GkyuX9LmubW/HqmSErIxnw6fx8OGUsVc/oJxJFbJjXQv
QS4PQZOVkJOn3sZr4hlMMLEKA7NSP9O9BiXCQIycrCDN6YlZ+0/c
-----END RSA PRIVATE KEY-----
HEREDOC
puts "=== Re-creating Tower objects ==="
@tower_data.update { |td| td['items'] = {} }
# create test organization
uri = '/api/v1/organizations/'
data = {"name" => 'spec_test_org', "description" => "for miq spec tests"}
organization = create_obj(uri, data, %w(id))
# create scm cred
uri = '/api/v1/credentials/'
data = {"name" => "hello_scm_cred", "kind" => "scm", "username" => "admin", "password" => "abc", "organization" => organization['id']}
scm_credential = create_obj(uri, data)
# create machine cred
data = {"name" => "hello_machine_cred", "kind" => "ssh", "username" => "admin", "password" => "abc", "organization" => organization['id']}
machine_credential = create_obj(uri, data)
# create vault cred
data = {"name" => "hello_vault_cred", "kind" => "ssh", "vault_password" => "abc", "organization" => organization['id']}
_vault_credential = create_obj(uri, data)
# create network cred
data = {"name" => "hello_network_cred", "kind" => "net", "username" => "admin", "password" => "abc", "organization" => organization['id']}
network_credential = create_obj(uri, data)
# create cloud aws cred
data = {"name" => "hello_aws_cred", "kind" => "aws", "username" => "ABC", "password" => "abc", "organization" => organization['id']}
aws_credential = create_obj(uri, data)
# create cloud openstack cred
data = {"name" => "hello_openstack_cred", "kind" => "openstack", "username" => "hello_rack", "password" => "abc", "host" => "openstack.com", "project" => "hello_rack", "organization" => organization['id']}
_openstack_credential = create_obj(uri, data)
# create cloud google cred
data = {"name" => "hello_gce_cred", "kind" => "gce", "username" => "hello_gce@gce.com", "ssh_key_data" => ssh_key_data, "project" => "squeamish-ossifrage-123", "organization" => organization['id']}
_gce_credential = create_obj(uri, data)
# create cloud azure(RM) cred
data = {"name" => "hello_azure_cred", "kind" => "azure_rm", "username" => "admin", "password" => "abc", "subscription" => "sub_id", "tenant" => "ten_id", "secret" => "my_secret", "client" => "cli_id", "organization" => organization['id']}
_azure_rm_credential = create_obj(uri, data)
# create cloud satellite6 cred
data = {"name" => "hello_sat_cred", "kind" => "satellite6", "username" => "admin", "password" => "abc", "host" => "s1.sat.com", "organization" => organization['id']}
_sat6_credential = create_obj(uri, data)
unless v3_2?
# These Credential types were removed from v3.2.
# create cloud rackspace cred
data = {"name" => "hello_rax_cred", "kind" => "rax", "username" => "admin", "password" => "abc", "organization" => organization['id']}
_rax_credential = create_obj(uri, data)
# create cloud azure(Classic) cred
data = {"name" => "hello_azure_classic_cred", "kind" => "azure", "username" => "admin", "ssh_key_data" => ssh_key_data, "organization" => organization['id']}
_azure_classic_credential = create_obj(uri, data)
end
# create inventory
uri = '/api/v1/inventories/'
data = {"name" => "hello_inventory", "description" => "inventory for miq spec tests", "organization" => organization['id']}
inventory = create_obj(uri, data, %w(id))
# create a host
uri = '/api/v1/hosts/'
data = {"name" => "hello_vm", "instance_id" => "4233080d-7467-de61-76c9-c8307b6e4830", "inventory" => inventory['id']}
create_obj(uri, data, %w(id))
# create a project
uri = '/api/v1/projects/'
data = {"name" => 'hello_repo', "scm_url" => "https://github.com/jameswnl/ansible-examples", "scm_type" => "git", "credential" => scm_credential['id'], "organization" => organization['id']}
project = create_obj(uri, data, %w(id status))
# Wait until there is a update job for "hello_repo".
uri = nil
project = try_get_obj_until(project['url']) do |body|
uri = body['related']['last_update']
uri.present?
end
# Wait until the "hello_repo" update finishes.
last_update = try_get_obj_until(uri) do |body|
raise "“hello repo” cloning failed." if body['failed']
body['finished'].present?
end
@tower_data.update { |td| td['items']['hello_repo']['status'] = last_update['status'] }
@tower_data.update { |td| td['items']['hello_repo']['last_updated'] = Time.parse(last_update['finished']).utc }
@tower_data.update { |td| td['items']['hello_repo']['playbooks'] = get_obj(project['related']['playbooks']) }
# create a job_template
uri = '/api/v1/job_templates/'
data = {"name" => 'hello_template', "description" => "test job", "job_type" => "run", "project" => project['id'], "playbook" => "hello_world.yml", "credential" => machine_credential['id'], "cloud_credential" => aws_credential['id'], "network_credential" => network_credential['id'], "inventory" => inventory['id'], "organization" => organization['id']}
create_obj(uri, data, %w(id))
# create a job_template with survey spec
uri = '/api/v1/job_templates/'
data = {"name" => "hello_template_with_survey", "description" => "test job with survey spec", "job_type" => "run", "project" => project['id'], "playbook" => "hello_world.yml", "credential" => machine_credential['id'], "inventory" => inventory['id'], "survey_enabled" => true, "organization" => organization['id']}
template = create_obj(uri, data, %w(id))
# create survey spec
uri = "/api/v1/job_templates/#{template['id']}/survey_spec/"
data = {"name" => "Simple Survey", "description" => "Description of the simple survey", "spec" => [{"type" => "text", "question_name" => "example question", "question_description" => "What is your favorite color?", "variable" => "favorite_color", "required" => false, "default" => "blue"}]}
@conn.post(uri, data).body
puts "Created #{template['url']} survey_spec"
# create another project
uri = '/api/v1/projects/'
data = {"name" => 'another_repo', "scm_url" => "https://github.com/jameswnl/ansible-examples", "scm_type" => "git", "credential" => scm_credential['id'], "organization" => organization['id']}
create_obj(uri, data)
self
end
def counts
puts "=== Object counts ==="
@tower_data.update { |td| td['counts'] = {} }
targets = {
'configuration_script' => 'job_templates',
'configuration_script_source' => 'projects',
'configured_system' => 'hosts',
'inventory_group' => 'inventories',
'credential' => 'credentials'
}
targets.each do |miq_name, tower_name|
count = get_obj("/api/v1/#{tower_name}/")['count']
puts("%s %s: %s" % [miq_name.ljust(30), "(#{tower_name})".ljust(20), count])
@tower_data.update { |td| td['counts'][tower_name] = {'total' => count} }
end
@tower_data.update { |td| td['counts']['playbooks'] = {'total' => 0} }
# Dump playbook count: total and for created projects
dumped_projects = %w(hello_repo)
uri = '/api/v1/projects/'
while uri
response = get_obj(uri)
uri = response['next']
response['results'].each do |result|
playbook_count = get_obj(result['related']['playbooks']).count
if dumped_projects.include?(result['name'])
@tower_data.update { |td| td['counts']['playbooks'][result['name']] = playbook_count }
end
@tower_data.update { |td| td['counts']['playbooks']['total'] += playbook_count }
end
end
# Dump playbook count: total and for created projects
tower_data = @tower_data.read
puts("%s %s: %s" % ['configuration_script_payload'.ljust(30),
"(playbooks)".ljust(20),
tower_data['counts']['playbooks']['total']])
tower_data['counts']['playbooks'].each do |name, count|
puts(" %s: %s" % [name.ljust(47), count]) if dumped_projects.include?(name)
end
self
end
end