ansible_spec_plus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # lib = File.expand_path('../lib', __FILE__)
3
+ # $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ # require 'ansible_spec/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "ansible_spec_plus"
8
+ gem.date = Time.now.strftime("%Y-%m-%d")
9
+ gem.version = "1.0.0"
10
+ gem.authors = ["Meik Minks"]
11
+ gem.email = ["mminks@inoxio.de"]
12
+ gem.description = %q{Ansible Config Parser for Serverspec to test roles, hosts and playbooks. Providing test coverage.}
13
+ gem.summary = %q{Ansible Config Parser for Serverspec to test roles, hosts and playbooks. Providing test coverage.}
14
+ gem.homepage = "https://github.com/consort-it/ansible_spec_plus"
15
+ gem.license = "MIT"
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency "bundler", "~> 1.3"
21
+ gem.add_development_dependency 'rake', '~> 0'
22
+ gem.add_development_dependency 'diff-lcs', '~> 0'
23
+ gem.add_development_dependency 'simplecov', '~> 0'
24
+
25
+ gem.add_runtime_dependency 'ansible_spec', '~> 0.2', '>= 0.2.19'
26
+ end
data/bin/asp ADDED
@@ -0,0 +1,72 @@
1
+ #! /usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ # TODO comment in again when ready
5
+ # require 'ansible_spec_plus'
6
+ require 'optparse'
7
+
8
+ require_relative '../lib/ansible_spec_plus'
9
+
10
+ ARGV.push('-h') if ARGV.empty?
11
+
12
+ KNOWN_RESOURCES = [
13
+ 'file',
14
+ 'template',
15
+ 'docker_container',
16
+ 'docker_image',
17
+ 'service',
18
+ 'apt',
19
+ 'pip',
20
+ 'gem'
21
+ ]
22
+
23
+ options = {}
24
+
25
+ opt_parser = OptionParser.new do |opt|
26
+ opt.banner = "Ansible Spec Plus is an addon to 'ansible_spec' which enables you to run
27
+ specs for Ansible roles, hosts and/or playbooks separately. Furthermore
28
+ it provides you with a simple resource coverage summary.
29
+
30
+ Usage: asp COMMAND [OPTIONS]"
31
+ opt.separator ""
32
+ opt.separator "Commands:"
33
+ opt.separator " list # list all available specs"
34
+ opt.separator " [rolespec|hostspec|playbookspec] list # list all available role/host/playbook specs"
35
+ opt.separator ""
36
+ opt.separator "Options:"
37
+
38
+ opt.on("-l", "--local", "running specs on local machine") do
39
+ ENV['BACKEND'] = 'exec'
40
+ end
41
+
42
+ opt.on("-h","--help","help") do
43
+ puts opt_parser
44
+ end
45
+ end
46
+
47
+ opt_parser.parse!
48
+
49
+ if ARGV[0] == 'list'
50
+ options[:list] = true
51
+ elsif ARGV[0] == 'rolespec'
52
+ if ARGV[1] == 'list'
53
+ options[:list_rolespec] = true
54
+ else
55
+ options[:run_rolespec] = ARGV[1]
56
+ end
57
+ elsif ARGV[0] == 'hostspec'
58
+ if ARGV[1] == 'list'
59
+ options[:list_hostspec] = true
60
+ else
61
+ options[:run_hostspec] = ARGV[1]
62
+ end
63
+ elsif ARGV[0] == 'playbookspec'
64
+ if ARGV[1] == 'list'
65
+ options[:list_playbookspec] = true
66
+ else
67
+ options[:run_playbookspec] = ARGV[1]
68
+ end
69
+ else
70
+ end
71
+
72
+ AnsibleSpecPlus.new.run(options)
data/bin/asp-init ADDED
@@ -0,0 +1,78 @@
1
+ #! /usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require "fileutils"
5
+
6
+ def safe_create_spec_helper
7
+ content = File.open(File.dirname(__FILE__) + "/../lib/src/spec/spec_helper.rb").read
8
+ safe_mkdir("spec")
9
+ safe_touch("spec/spec_helper.rb")
10
+ File.open("spec/spec_helper.rb", 'w') do |f|
11
+ f.puts content
12
+ end
13
+
14
+ end
15
+
16
+ def safe_create_ansiblespec
17
+ content = File.open(File.dirname(__FILE__) + "/../lib/src/.ansiblespec").read
18
+ safe_touch(".ansiblespec")
19
+ File.open(".ansiblespec", 'w') do |f|
20
+ f.puts content
21
+ end
22
+ end
23
+
24
+ def safe_create_rspec
25
+ content = File.open(File.dirname(__FILE__) + "/../lib/src/.rspec").read
26
+ safe_touch(".rspec")
27
+ File.open(".rspec", 'w') do |f|
28
+ f.puts content
29
+ end
30
+ end
31
+
32
+ def safe_mkdir(dir)
33
+ unless FileTest.exist?("#{dir}")
34
+ FileUtils.mkdir_p("#{dir}")
35
+ TermColor.green
36
+ puts "\t\tcreate\t#{dir}"
37
+ TermColor.reset
38
+ else
39
+ TermColor.red
40
+ puts "\t\texists\t#{dir}"
41
+ TermColor.reset
42
+ end
43
+ end
44
+
45
+ def safe_touch(file)
46
+ unless File.exists? "#{file}"
47
+ File.open("#{file}", 'w') do |f|
48
+ #f.puts content
49
+ end
50
+ TermColor.green
51
+ puts "\t\tcreate\t#{file}"
52
+ TermColor.reset
53
+ else
54
+ TermColor.red
55
+ puts "\t\texists\t#{file}"
56
+ TermColor.reset
57
+ end
58
+ end
59
+
60
+ class TermColor
61
+ class << self
62
+ def reset ; c 0 ; end
63
+
64
+ def red ; c 31; end
65
+
66
+ def green ; c 32; end
67
+
68
+ def c(num)
69
+ print "\e[#{num.to_s}m"
70
+ end
71
+ end
72
+ end
73
+
74
+ safe_create_spec_helper
75
+ safe_create_ansiblespec
76
+ safe_create_rspec
77
+
78
+ exit 0
@@ -0,0 +1,653 @@
1
+ require_relative '../lib/helpers/log'
2
+ require_relative '../lib/ansiblespec_helper'
3
+
4
+ require 'rake'
5
+ require 'rspec/core/rake_task'
6
+ require 'yaml'
7
+ require 'ansible_spec'
8
+ require 'pp'
9
+ require 'json'
10
+
11
+ class AnsibleSpecPlus
12
+ include Helpers::Log
13
+
14
+ if ENV['BASE_DIR']
15
+ BASE_DIR = ENV['BASE_DIR']
16
+ else
17
+ BASE_DIR = './'
18
+ end
19
+
20
+ ##################
21
+ # COMMON METHODS #
22
+ ##################
23
+
24
+ def run(options)
25
+ list_all_specs if options[:list] == true
26
+
27
+ list_role_specs if options[:list_rolespec] == true
28
+ list_host_specs if options[:list_hostspec] == true
29
+ list_playbook_specs if options[:list_playbookspec] == true
30
+
31
+ run_role_spec(options[:run_rolespec]) if options[:run_rolespec]
32
+ run_host_spec(options[:run_hostspec]) if options[:run_hostspec]
33
+ run_playbook_spec(options[:run_playbookspec]) if options[:run_playbookspec]
34
+ end
35
+
36
+ def list_all_specs
37
+ list_role_specs
38
+ list_host_specs
39
+ list_playbook_specs
40
+ end
41
+
42
+ def check_for_specs_in_file(file)
43
+ File.readlines(file).grep(/describe\s{1}/).any?
44
+ end
45
+
46
+ def analyze_resources(resources)
47
+ analyzed_resources = []
48
+
49
+ resources.each do |resource|
50
+ resource_type = nil
51
+
52
+ resource.keys.each do |key|
53
+ resource_type = key if KNOWN_RESOURCES.include?(key)
54
+ end
55
+
56
+ if resource_type.nil?
57
+ log.warn "Unknown resource: #{resource}"
58
+ next
59
+ end
60
+
61
+ skip = false
62
+
63
+ if resource.values[1].respond_to?(:each)
64
+ resource.values[1].each do |key, value|
65
+ skip = true if value =~ /\{\{/
66
+ end
67
+ else
68
+ skip = true if resource.values[1] =~ /\{\{/
69
+ end
70
+
71
+ if skip == true
72
+ log.warn "Don't know how to deal with '{{ }}' syntax: #{resource}"
73
+ next
74
+ end
75
+
76
+ if resource_type == 'file' || resource_type == 'template'
77
+ resource_type = 'File'
78
+ if resource.values[1].respond_to?(:each)
79
+ target = resource.values[1].select { |i| i =~ /path|dest/ }
80
+ resource_name = target.values[0]
81
+ else
82
+ target = resource.values[1].split(" ").select { |i| i =~ /path|dest/ }
83
+ resource_name = target.first.gsub(/.*=/,'')
84
+ end
85
+ elsif resource_type == 'docker_container'
86
+ resource_type = 'Docker container'
87
+ resource_name = resource.values[1]['name']
88
+ elsif resource_type == 'docker_image'
89
+ resource_type = 'Docker image'
90
+ resource_name = resource.values[1]['name']
91
+ elsif resource_type == 'service'
92
+ resource_type = 'Service'
93
+ if resource.values[1].respond_to?(:each)
94
+ resource_name = resource.values[1]['name']
95
+ else
96
+ resource_name = resource.values[1].split(" ")[0].gsub(/.*=/,'')
97
+ end
98
+ elsif resource_type =~ /apt|pip|gem/
99
+ if (resource_type == 'apt') && (! resource['apt'].include?('name'))
100
+ log.warn "Unknown resource: #{resource}"
101
+ next
102
+ end
103
+
104
+ resource_type = 'Package'
105
+ resource.each do |item|
106
+ next unless item[0] =~ /apt|pip|gem/
107
+
108
+ resource_name = item[1]['name']
109
+ end
110
+ else
111
+ next
112
+ end
113
+
114
+ analyzed_resources << "#{resource_type} \"#{resource_name}\""
115
+ end
116
+
117
+ return analyzed_resources
118
+ end
119
+
120
+ def get_hosts_from_vai_host_file
121
+ inventory_hosts = []
122
+ hosts_with_vagrant_vars = {}
123
+
124
+ Dir.chdir(BASE_DIR) do
125
+ begin
126
+ File.open('hosts', 'r') do |file|
127
+ file.each_line do |line|
128
+ pattern = /^#.*|^$\n|^\[.*|^\r\n?/
129
+ next if line =~ pattern
130
+ inventory_hosts << line
131
+ end
132
+ end
133
+ rescue => e
134
+ log.error "hosts file doesn't exist: #{e}"
135
+ end
136
+ end
137
+
138
+ inventory_hosts.each do |line|
139
+ hostname = line.split(' ').first
140
+
141
+ parts = line.match(/\s.*/).to_s.split(' ')
142
+
143
+ vars = {}
144
+ vars['name'] = hostname
145
+ parts.each do |part|
146
+ key = part.gsub(/=.*/,'')
147
+ value = part.gsub(/.*=/,'').gsub(/'|"/,'')
148
+ vars["#{key}"] = value
149
+ end
150
+
151
+ hosts_with_vagrant_vars[hostname] = [vars]
152
+ end
153
+
154
+ return hosts_with_vagrant_vars
155
+ end
156
+
157
+ def print_rounded_role_coverage(all_resources, differences)
158
+ if all_resources.count == 0
159
+ return "0%"
160
+ else
161
+ "#{((all_resources - differences).count.to_f / all_resources.count.to_f * 100.0).round}%"
162
+ end
163
+ end
164
+
165
+ def calculate_coverage(type, name)
166
+ Dir.chdir(BASE_DIR) do
167
+ json_report = File.read('report.json')
168
+ parsed_report = JSON.parse(json_report)
169
+
170
+ case type
171
+ when 'role'
172
+ all_known_resources = analyze_resources(load_role_resources(name))
173
+ when 'host'
174
+ all_known_resources = analyze_resources(load_host_resources(name))
175
+ when 'playbook'
176
+ all_known_resources = analyze_resources(load_playbook_resources(name))
177
+ else
178
+ raise "Unknow type '#{type}'. Should be either role, host or playbook."
179
+ end
180
+
181
+ tested_resources = []
182
+
183
+ parsed_report['examples'].each do |example|
184
+ tested_resources << example['full_description'].gsub(/"\s{1}.*/,'"')
185
+ end
186
+
187
+ tested_resources = tested_resources.uniq
188
+
189
+ differences = []
190
+
191
+ all_known_resources.each do |resource|
192
+ differences << resource if ! tested_resources.include?(resource)
193
+ end
194
+
195
+ puts "Total resources: #{all_known_resources.count}"
196
+ puts "Touched resources: #{(all_known_resources - differences).count}"
197
+ puts "Resource coverage: #{print_rounded_role_coverage(all_known_resources, differences)}"
198
+
199
+ if differences.count > 0
200
+ puts "\nUncovered resources:"
201
+ differences.each do |item|
202
+ puts "- #{item}"
203
+ end
204
+ end
205
+ end
206
+ end
207
+
208
+ ################
209
+ # ROLE METHODS #
210
+ ################
211
+
212
+ def list_role_specs
213
+ get_roles_with_specs.each do |role|
214
+ command = "asp rolespec #{role}"
215
+ description = "# run role specs for #{role}"
216
+
217
+ puts "#{command} #{description.rjust(40)}"
218
+ end
219
+ end
220
+
221
+ def run_role_spec(role)
222
+ if check_role_directory_available(role) && check_role_specs_available(role)
223
+ create_role_rake_task(role)
224
+
225
+ Dir.chdir(BASE_DIR) do
226
+ Rake.application["#{role}"].invoke()
227
+ end
228
+
229
+ calculate_coverage('role', role)
230
+ end
231
+ end
232
+
233
+ def get_all_roles
234
+ all_roles = []
235
+
236
+ Dir.chdir(BASE_DIR) do
237
+ Dir.glob("roles/*").each do |role|
238
+ all_roles << File.basename(role)
239
+ end
240
+ end
241
+
242
+ return all_roles
243
+ end
244
+
245
+ def get_roles_with_specs
246
+ roles_with_specs = []
247
+
248
+ Dir.chdir(BASE_DIR) do
249
+ get_all_roles.each do |role|
250
+ successes = 0
251
+
252
+ Dir.glob("roles/#{role}/spec/*_spec.rb").each do |file|
253
+ successes =+ 1 if File.size(file) > 1
254
+ end
255
+
256
+ roles_with_specs << File.basename(role) if successes > 0
257
+ end
258
+ end
259
+
260
+ return roles_with_specs
261
+ end
262
+
263
+ def get_roles_without_specs
264
+ get_all_roles - get_roles_with_specs
265
+ end
266
+
267
+ def check_role_directory_available(role)
268
+ Dir.chdir(BASE_DIR) do
269
+ if ! Dir.exists?("roles/#{role}")
270
+ log.error "Directory 'roles/#{role}' does not exist. That's strange, isn't it?"
271
+ return false
272
+ end
273
+ end
274
+
275
+ return true
276
+ end
277
+
278
+ def check_role_specs_available(role)
279
+ Dir.chdir(BASE_DIR) do
280
+ successes = 0
281
+
282
+ Dir.glob("roles/#{role}/spec/*_spec.rb").each do |file|
283
+ successes =+ 1 if File.size(file) > 1
284
+ end
285
+
286
+ if successes == 0
287
+ # log.error "'#{role}' does not have specs but you requested me to run specs. Huu?"
288
+ return false
289
+ end
290
+ end
291
+
292
+ return true
293
+ end
294
+
295
+ def get_hosts_where_role_is_used(role)
296
+ role_used_in_hosts = []
297
+
298
+ Dir.chdir(BASE_DIR) do
299
+ YAML.load_file("site.yml").each do |playbook|
300
+ YAML.load_file(playbook['include'].to_s).each do |site|
301
+ site['roles'].each do |playbook_role|
302
+ if playbook_role.respond_to?(:each)
303
+ role_used_in_hosts << site['name'].to_s if playbook_role['role'].include?(role)
304
+ else
305
+ role_used_in_hosts << site['name'].to_s if playbook_role.include?(role)
306
+ end
307
+ end
308
+ end
309
+ end
310
+ end
311
+
312
+ return role_used_in_hosts
313
+ end
314
+
315
+ def load_role_resources(name)
316
+ resources = []
317
+
318
+ Dir.chdir(BASE_DIR) do
319
+ Dir.glob("roles/#{name}/tasks/*.yml").each do |file|
320
+ AnsibleSpec.load_playbook(file).each do |resource|
321
+ resources << resource
322
+ end
323
+ end
324
+ end
325
+
326
+ return resources
327
+ end
328
+
329
+ def create_role_rake_task(role)
330
+ Dir.chdir(BASE_DIR) do
331
+ properties = AnsibleSpecHelper.get_properties
332
+ cfg = AnsibleSpec::AnsibleCfg.new
333
+ get_hosts_where_role_is_used = get_hosts_where_role_is_used(role)
334
+
335
+ properties.each do |property|
336
+ next unless property['name'] == get_hosts_where_role_is_used.first
337
+
338
+ if property['hosts'].empty?
339
+ if ! get_hosts_from_vai_host_file.keys.include?(get_hosts_where_role_is_used.first)
340
+ raise "Uuups. I cannot find '#{get_hosts_where_role_is_used.first}' in your hosts file. 'vagrant up #{get_hosts_where_role_is_used.first}' may help."
341
+ end
342
+
343
+ get_hosts_from_vai_host_file.each do |host, values|
344
+ values.each do |property|
345
+ next unless property['name'] == get_hosts_where_role_is_used.first
346
+
347
+ RSpec::Core::RakeTask.new(role.to_sym) do |t|
348
+ log.info "Run role tests for #{role} on #{get_hosts_where_role_is_used.first} (#{property["ansible_ssh_host"]}:#{property["ansible_ssh_port"]})"
349
+
350
+ ENV['TARGET_HOST'] = property["ansible_ssh_host"]
351
+ ENV['TARGET_PORT'] = property["ansible_ssh_port"].to_s
352
+ ENV['TARGET_PRIVATE_KEY'] = property["ansible_ssh_private_key_file"]
353
+ ENV['TARGET_USER'] = property["ansible_ssh_user"]
354
+
355
+ t.pattern = '{' + cfg.roles_path.join(',') + '}/{' + role + '}/spec/*_spec.rb'
356
+ end
357
+ end
358
+ end
359
+ else
360
+ property['hosts'].each do |host|
361
+ RSpec::Core::RakeTask.new(role.to_sym) do |t|
362
+ log.info "Run role tests for #{role} on #{get_hosts_where_role_is_used.first} (#{host['uri']})"
363
+
364
+ ENV['TARGET_HOST'] = host['uri']
365
+
366
+ t.pattern = '{' + cfg.roles_path.join(',') + '}/{' + role + '}/spec/*_spec.rb'
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+ ################
375
+ # HOST METHODS #
376
+ ################
377
+
378
+ def list_host_specs
379
+ get_hosts_with_specs.each do |host|
380
+ command = "asp hostspec #{host}"
381
+ description = "# run host specs for #{host}"
382
+
383
+ puts "#{command} #{description.rjust(40)}"
384
+ end
385
+ end
386
+
387
+ def create_host_rake_task(host)
388
+ Dir.chdir(BASE_DIR) do
389
+ properties = AnsibleSpecHelper.get_properties
390
+ cfg = AnsibleSpec::AnsibleCfg.new
391
+
392
+ properties.each do |property|
393
+ next unless property['name'] == host
394
+
395
+ if property['hosts'].empty?
396
+ get_hosts_from_vai_host_file.each do |host, values|
397
+ values.each do |property|
398
+ RSpec::Core::RakeTask.new(host.to_sym) do |t|
399
+ log.info "Run host tests for #{host}"
400
+
401
+ ENV['TARGET_HOST'] = property["ansible_ssh_host"]
402
+ ENV['TARGET_PORT'] = property["ansible_ssh_port"].to_s
403
+ ENV['TARGET_PRIVATE_KEY'] = property["ansible_ssh_private_key_file"]
404
+ ENV['TARGET_USER'] = property["ansible_ssh_user"]
405
+
406
+ t.pattern = "spec/#{host}/*_spec.rb"
407
+ end
408
+ end
409
+ end
410
+ else
411
+ property['hosts'].each do |host|
412
+ RSpec::Core::RakeTask.new(property["name"].to_sym) do |t|
413
+ log.info "Run host tests for #{property["name"]}"
414
+
415
+ ENV['TARGET_HOST'] = host['uri']
416
+
417
+ t.pattern = "spec/#{property["name"]}/*_spec.rb"
418
+ end
419
+ end
420
+ end
421
+ end
422
+ end
423
+ end
424
+
425
+ def run_host_spec(host)
426
+ create_host_rake_task(host)
427
+
428
+ Dir.chdir(BASE_DIR) do
429
+ Rake.application.invoke_task("#{host}")
430
+ end
431
+
432
+ calculate_coverage('host', host)
433
+ end
434
+
435
+ def load_host_resources(name)
436
+ resources = []
437
+
438
+ Dir.chdir(BASE_DIR) do
439
+ YAML.load_file('./site.yml').each do |site|
440
+ next unless site.values[0] =~ /#{name}\.(yml|yaml)/
441
+
442
+ playbook_path = site.values[0]
443
+
444
+ AnsibleSpec.load_playbook(playbook_path).each do |playbook|
445
+ next if playbook['tasks'].nil?
446
+
447
+ playbook['tasks'].map { |task| resources << task }
448
+ end
449
+ end
450
+ end
451
+
452
+ return resources.flatten
453
+ end
454
+
455
+ def get_hosts_with_specs
456
+ hosts_with_specs = []
457
+
458
+ get_vagrant_or_regular_ansible_hosts.each do |host|
459
+ hosts_with_specs << host if check_for_host_specs(host)
460
+ end
461
+
462
+ return hosts_with_specs.uniq
463
+ end
464
+
465
+ def get_vagrant_or_regular_ansible_hosts
466
+ hosts = []
467
+
468
+ Dir.chdir(BASE_DIR) do
469
+ properties = AnsibleSpecHelper.get_properties
470
+ cfg = AnsibleSpec::AnsibleCfg.new
471
+
472
+ properties.each do |property|
473
+ if property['hosts'].empty?
474
+ get_hosts_from_vai_host_file.each do |host, values|
475
+ values.each do |property|
476
+ hosts << property['name'] if check_for_existing_playbook(property['name'])
477
+ end
478
+ end
479
+ else
480
+ property['hosts'].each do |host|
481
+ hosts << property['name'] if check_for_existing_playbook(property['name'])
482
+ end
483
+ end
484
+ end
485
+ end
486
+
487
+ return hosts
488
+ end
489
+
490
+ def check_for_host_specs(host)
491
+ Dir.chdir(BASE_DIR) do
492
+ if File.directory?("./spec/#{host}")
493
+ Dir.glob("./spec/#{host}/*_spec.rb").each do |file|
494
+ if check_for_specs_in_file(file)
495
+ return true
496
+ else
497
+ return false
498
+ end
499
+ end
500
+ else
501
+ return false
502
+ end
503
+ end
504
+ end
505
+
506
+ def get_roles_of_host(host)
507
+ roles_with_specs = []
508
+
509
+ Dir.chdir(BASE_DIR) do
510
+ playbook_path = ''
511
+
512
+ YAML.load_file('./site.yml').each do |site|
513
+ next unless site.values[0] =~ /#{host}\.(yml|yaml)/
514
+
515
+ playbook_path = site.values[0]
516
+ end
517
+
518
+ YAML.load_file(playbook_path).each do |playbook|
519
+ playbook['roles'].each do |role|
520
+ roles_with_specs << role if check_role_specs_available(role)
521
+ end
522
+ end
523
+ end
524
+
525
+ return roles_with_specs.uniq
526
+ end
527
+
528
+ ####################
529
+ # PLAYBOOK METHODS #
530
+ ####################
531
+
532
+ def list_playbook_specs
533
+ get_playbooks_with_host_and_or_role_specs.each do |playbook|
534
+ command = "asp playbookspec #{playbook}"
535
+ description = "# run playbook specs (host specs and role specs) for #{playbook} playbook"
536
+
537
+ puts "#{command} #{description.rjust(77)}"
538
+ end
539
+ end
540
+
541
+ def run_playbook_spec(playbook)
542
+ create_playbook_rake_task(playbook)
543
+
544
+ Dir.chdir(BASE_DIR) do
545
+ Rake.application.invoke_task("#{playbook}")
546
+ end
547
+
548
+ calculate_coverage('playbook', playbook)
549
+ end
550
+
551
+ def create_playbook_rake_task(playbook)
552
+ ansiblespec_roles = []
553
+
554
+ hostname = playbook.gsub(/\.yml|\.yaml/,'')
555
+
556
+ get_roles_of_host(hostname).each do |role|
557
+ ansiblespec_roles << role if check_role_specs_available(role)
558
+ end
559
+
560
+ Dir.chdir(BASE_DIR) do
561
+ properties = AnsibleSpecHelper.get_properties
562
+ cfg = AnsibleSpec::AnsibleCfg.new
563
+
564
+ if properties.select { |item| item['name'] == hostname}[0]['hosts'].empty?
565
+ get_hosts_from_vai_host_file.select { |name,_| name == hostname }.each do |item|
566
+ ENV['TARGET_HOST'] = item.flatten.last['ansible_ssh_host']
567
+ ENV['TARGET_PORT'] = item.flatten.last['ansible_ssh_port']
568
+ ENV['TARGET_PRIVATE_KEY'] = item.flatten.last['ansible_ssh_private_key_file']
569
+ ENV['TARGET_USER'] = item.flatten.last['ansible_ssh_user']
570
+ end
571
+ else
572
+ ENV['TARGET_HOST'] = properties.select { |item| item['name'] == hostname}[0]['hosts'][0]['uri']
573
+ end
574
+
575
+ RSpec::Core::RakeTask.new("#{hostname}".to_sym) do |t|
576
+ log.info "Run playbook tests for #{hostname}"
577
+
578
+ roles_pattern = ansiblespec_roles.nil? ? '' : ",{#{cfg.roles_path.join(',')}}/{#{ansiblespec_roles.uniq.join(',')}}/spec/*_spec.rb"
579
+ host_pattern = check_for_host_specs(hostname) ? ",spec/#{hostname}/*_spec.rb" : ''
580
+
581
+ t.pattern = roles_pattern + host_pattern
582
+ end
583
+ end
584
+ end
585
+
586
+ def load_playbook_resources(name)
587
+ resources = []
588
+
589
+ # collect role resources
590
+ Dir.chdir(BASE_DIR) do
591
+ YAML.load_file('./site.yml').each do |site|
592
+ next unless site.values[0] =~ /#{name}\.(yml|yaml)/
593
+
594
+ playbook_path = site.values[0]
595
+
596
+ AnsibleSpec.load_playbook(playbook_path).each do |playbook|
597
+ playbook['roles'].map { |role| resources << load_role_resources(role) }
598
+ end
599
+ end
600
+ end
601
+
602
+ # collect host resources
603
+ resources = resources.flatten + load_host_resources(name)
604
+
605
+ return resources
606
+ end
607
+
608
+ def check_for_existing_playbook(host)
609
+ Dir.chdir(BASE_DIR) do
610
+ if File.exists?("#{host}.yml")
611
+ return true
612
+ else
613
+ return false
614
+ end
615
+ end
616
+ end
617
+
618
+ def get_playbooks_host_spec_summary
619
+ playbooks = []
620
+
621
+ Dir.chdir(BASE_DIR) do
622
+ YAML.load_file('./site.yml').each do |site|
623
+ Dir.glob(site.values[0]).each do |playbook|
624
+ playbook = File.basename(playbook)
625
+ host = playbook.gsub(/\.yml|\.yaml/,'')
626
+
627
+ playbooks << { playbook => check_for_host_specs(host) }
628
+ end
629
+ end
630
+ end
631
+
632
+ return playbooks.uniq
633
+ end
634
+
635
+ def get_playbooks_with_host_and_or_role_specs
636
+ playbooks = []
637
+
638
+ get_playbooks_host_spec_summary.each do |entry|
639
+ host = entry.keys[0].gsub(/\.yml|\.yaml/,'')
640
+ has_specs = entry.values[0]
641
+
642
+ if has_specs
643
+ playbooks << host
644
+ else
645
+ get_roles_of_host(host).each do |role|
646
+ playbooks << host if check_role_specs_available(role)
647
+ end
648
+ end
649
+ end
650
+
651
+ return playbooks.uniq
652
+ end
653
+ end