ansible_spec_plus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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