puppet_litmus 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a75172285da5913803f07bae8651183d7196cd14
4
- data.tar.gz: 45d70cbc2fcc22010f38a29b10f022d74ae5bae5
3
+ metadata.gz: 071a673e5f77fa53f54031196856229f59a8869b
4
+ data.tar.gz: d35953f4b2d720a7f185c558ff71ea21964db698
5
5
  SHA512:
6
- metadata.gz: 6053495d1f61e0a8c671b81cd50048f6cb064431806950a8d93ab79510290e6168470fbfd3991c97833bbcb01a1c5ac89c80ee0ad150680c07e2e1f8d7cb802f
7
- data.tar.gz: ccc9d916d4a6f56c138bfdbb6767e5f2c20bb059d5fcfb20d5f332f47e59635acde327b20585140ccf5529f0c7d91163a5b41d3b0f2bcb6712b12effe33bb12b
6
+ metadata.gz: da87c6046e0eddf2873ce385a95fb772cdbc92acf62525f588d1e86f6b10b43bde52634a9a228ceb99ad3f22a48ae16c44d0f387e0c31a069e59a8e7378dc9c8
7
+ data.tar.gz: ca340854e2b2f81d0205c30a9a07a13343c0f75ad67879a38c405f1d5962cc427ca783a71e301d90e1804c69e0f23105eb0b4110746f0768f41d22d68a4f3d46
@@ -6,7 +6,6 @@ require 'bolt_spec/run'
6
6
  require 'open3'
7
7
  require 'pdk'
8
8
  require 'json'
9
- require 'parallel'
10
9
 
11
10
  def get_metadata_operating_systems(metadata)
12
11
  return unless metadata.is_a?(Hash)
@@ -110,28 +109,18 @@ namespace :litmus do
110
109
  config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
111
110
  raise "the provision module was not found in #{config_data['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(config_data['modulepath'], 'provision'))
112
111
 
113
- if %w[abs vmpooler].include?(args[:provisioner])
114
- params = { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd }
115
- results = run_task("provision::#{args[:provisioner]}", 'localhost', params, config: config_data, inventory: nil)
116
- results.each do |result|
117
- if result['status'] != 'success'
118
- puts "Failed #{result['node']}\n#{result}"
119
- else
120
- puts "#{result['result']['node_name']}, #{args[:platform]}"
121
- end
122
- end
123
- elsif args[:provisioner] == 'docker'
124
- params = { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd }
125
- results = run_task('provision::docker', 'localhost', params, config: config_data, inventory: nil)
126
- results.each do |result|
127
- if result['status'] != 'success'
128
- puts "Failed #{result['node']}\n#{result}"
129
- else
130
- puts "#{result['result']['node_name']}, #{args[:platform]}"
131
- end
112
+ unless %w[abs vmpooler docker vagrant].include?(args[:provisioner])
113
+ raise "Unknown provisioner '#{args[:provisioner]}', try abs/docker/vmpooler/vagrant"
114
+ end
115
+
116
+ params = { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd }
117
+ results = run_task("provision::#{args[:provisioner]}", 'localhost', params, config: config_data, inventory: nil)
118
+ results.each do |result|
119
+ if result['status'] != 'success'
120
+ puts "Failed #{result['node']}\n#{result}"
121
+ else
122
+ puts "#{result['result']['node_name']}, #{args[:platform]}"
132
123
  end
133
- else
134
- raise "Unknown provisioner '#{args[:provisioner]}', try abs/docker/vmpooler"
135
124
  end
136
125
  end
137
126
 
@@ -218,7 +207,7 @@ namespace :litmus do
218
207
  targets.each do |node_name|
219
208
  # how do we know what provisioner to use
220
209
  node_facts = facts_from_node(inventory_hash, node_name)
221
- next unless %w[abs docker vmpooler].include?(node_facts['provisioner'])
210
+ next unless %w[abs docker vmpooler vagrant].include?(node_facts['provisioner'])
222
211
 
223
212
  params = { 'action' => 'tear_down', 'node_name' => node_name, 'inventory' => Dir.pwd }
224
213
  result = run_task("provision::#{node_facts['provisioner']}", 'localhost', params, config: config_data, inventory: nil)
@@ -240,32 +229,66 @@ namespace :litmus do
240
229
  include PuppetLitmus::InventoryManipulation
241
230
  if File.file?('inventory.yaml')
242
231
  inventory_hash = inventory_hash_from_inventory_file
243
- hosts = find_targets(inventory_hash, nil)
232
+ targets = find_targets(inventory_hash, nil)
244
233
 
245
234
  desc 'Run tests in parallel against all machines in the inventory file'
246
235
  task :parallel do
247
- args = []
248
- hosts.each do |host|
249
- args << ["TARGET_HOST=#{host} bundle exec rspec ./spec/acceptance --format progress --format html --out html/#{host}.html", host]
236
+ spinners = TTY::Spinner::Multi.new("Running against #{targets.size} targets.[:spinner]", frames: ['.'], interval: 0.1)
237
+ payloads = []
238
+ targets.each do |target|
239
+ test = "TARGET_HOST=#{target} bundle exec rspec ./spec/acceptance --format progress"
240
+ title = "#{target}, #{facts_from_node(inventory_hash, target)['platform']}"
241
+ payloads << [title, test]
250
242
  end
251
- results = Parallel.map(args, progress: "Running against #{hosts.size} machines") do |test, host|
252
- stdout, stderr, status = Open3.capture3(test)
253
- ["================\n#{host}\n", stdout, stderr, status]
243
+
244
+ results = []
245
+ success_list = []
246
+ failure_list = []
247
+ if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
248
+ # CI systems are strange beasts, we only output a '.' every wee while to keep the terminal alive.
249
+ puts "Running against #{targets.size} targets.\n"
250
+ spinner = TTY::Spinner.new(':spinner', frames: ['.'], interval: 0.1)
251
+ spinner.auto_spin
252
+ results = Parallel.map(payloads) do |title, test|
253
+ stdout, stderr, status = Open3.capture3(test)
254
+ ["================\n#{title}\n", stdout, stderr, status]
255
+ end
256
+ spinner.success
257
+ else
258
+ spinners = TTY::Spinner::Multi.new("[:spinner] Running against #{targets.size} targets.")
259
+ payloads.each do |title, test|
260
+ spinners.register("[:spinner] #{title}") do |sp|
261
+ stdout, stderr, status = Open3.capture3(test)
262
+ if status.to_i.zero?
263
+ sp.success
264
+ success_list.push(title)
265
+ else
266
+ sp.error
267
+ failure_list.push(title)
268
+ end
269
+ results.push(["================\n#{title}\n", stdout, stderr, status])
270
+ end
271
+ end
272
+ spinners.auto_spin
273
+ spinners.success
254
274
  end
255
- # if any result is nonzero, there were test failures
256
- failures = false
275
+
276
+ # output test results
257
277
  results.each do |result|
258
- failures = true unless result.last.exitstatus.zero?
259
278
  puts result
260
279
  end
261
- exit 1 if failures
280
+
281
+ # output test summary
282
+ puts "Successful on #{success_list.size} nodes: #{success_list}" if success_list.any?
283
+ puts "Failed on #{failure_list.size} nodes: #{failure_list}" if failure_list.any?
284
+ exit 1 if failure_list.any?
262
285
  end
263
286
 
264
- hosts.each do |host|
265
- desc "Run serverspec against #{host}"
266
- RSpec::Core::RakeTask.new(host.to_sym) do |t|
287
+ targets.each do |target|
288
+ desc "Run serverspec against #{target}"
289
+ RSpec::Core::RakeTask.new(target.to_sym) do |t|
267
290
  t.pattern = 'spec/acceptance/**{,/*/**}/*_spec.rb'
268
- ENV['TARGET_HOST'] = host
291
+ ENV['TARGET_HOST'] = target
269
292
  end
270
293
  end
271
294
  end
@@ -1,14 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # helper functions for running puppet commands, and helpers
3
+ # helper functions for running puppet commands. They execute a target system specified by ENV['TARGET_HOST']
4
+ # heavily uses functions from here https://github.com/puppetlabs/bolt/blob/master/developer-docs/bolt_spec-run.md
4
5
  module PuppetLitmus::Serverspec
6
+ # Applies a manifest twice. First checking for errors. Secondly to make sure no changes occur.
7
+ #
8
+ # @param manifest [String] puppet manifest code to be applied.
9
+ # @return [Boolean] The result of the 2 apply manifests.
5
10
  def idempotent_apply(manifest)
6
11
  manifest_file_location = create_manifest_file(manifest)
7
12
  apply_manifest(nil, catch_failures: true, manifest_file_location: manifest_file_location)
8
13
  apply_manifest(nil, catch_changes: true, manifest_file_location: manifest_file_location)
9
14
  end
10
15
 
16
+ # rubocop:disable Layout/TrailingWhitespace
17
+
18
+ # Applies a manifest. returning the result of that apply. Mimics the apply_manifest from beaker
19
+ #
20
+ # @param manifest [String] puppet manifest code to be applied.
21
+ # @param opts [Hash] Alters the behaviour of the command. Valid options are:
22
+ # :catch_changes [Boolean] exit status of 1 if there were changes.
23
+ # :expect_failures [Boolean] doesnt return an exit code of non-zero if the apply failed.
24
+ # :manifest_file_location [Path] The place on the target system.
25
+ # :prefix_command [String] prefixes the puppet apply command; eg "export LANGUAGE='ja'".
26
+ # :debug [Boolean] run puppet apply with the debug flag.
27
+ # @param [Block] his method will yield to a block of code passed by the caller; this can be used for additional validation, etc.
28
+ # @return [Object] A result object from the apply.
11
29
  def apply_manifest(manifest, opts = {})
30
+ # rubocop:enable Layout/TrailingWhitespace
12
31
  target_node_name = ENV['TARGET_HOST']
13
32
  raise 'manifest and manifest_file_location in the opts hash are mutually exclusive arguments, pick one' if !manifest.nil? && !opts[:manifest_file_location].nil?
14
33
  raise 'please pass a manifest or the manifest_file_location in the opts hash' if (manifest.nil? || manifest == '') && opts[:manifest_file_location].nil?
@@ -19,9 +38,10 @@ module PuppetLitmus::Serverspec
19
38
  else
20
39
  inventory_hash_from_inventory_file
21
40
  end
22
- command_to_run = "puppet apply #{manifest_file_location}"
41
+ command_to_run = "#{opts[:prefix_command]} puppet apply #{manifest_file_location}"
23
42
  command_to_run += " --modulepath #{Dir.pwd}/spec/fixtures/modules" if target_node_name.nil? || target_node_name == 'localhost'
24
43
  command_to_run += ' --detailed-exitcodes' if !opts[:catch_changes].nil? && (opts[:catch_changes] == true)
44
+ command_to_run += ' --debug' if !opts[:debug].nil? && (opts[:debug] == true)
25
45
  # BOLT-608
26
46
  if Gem.win_platform?
27
47
  stdout, stderr, status = Open3.capture3(command_to_run)
@@ -35,13 +55,22 @@ module PuppetLitmus::Serverspec
35
55
  result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
36
56
  end
37
57
 
38
- raise "apply mainfest failed\n`#{command_to_run}`\n======\n#{result}" if result.first['result']['exit_code'] != 0 && opts[:expect_failures] != true
58
+ raise "apply manifest failed\n`#{command_to_run}`\n======\n#{result}" if result.first['result']['exit_code'] != 0 && opts[:expect_failures] != true
39
59
 
40
- result.first
60
+ result = OpenStruct.new(exit_code: result.first['result']['exit_code'],
61
+ stdout: result.first['result']['stdout'],
62
+ stderr: result.first['result']['stderr'])
63
+ yield result if block_given?
64
+ result
41
65
  end
42
66
 
43
- # creates a temp manifest file locally & remote depending on target
67
+ # Creates a manifest file locally, if running against localhost create in a temp location. Or create it on the target system.
68
+ #
69
+ # @param manifest [String] puppet manifest code.
70
+ # @return [String] The path to the location of the manifest.
44
71
  def create_manifest_file(manifest)
72
+ require 'tempfile'
73
+
45
74
  target_node_name = ENV['TARGET_HOST']
46
75
  manifest_file = Tempfile.new(['manifest_', '.pp'])
47
76
  manifest_file.write(manifest)
@@ -59,6 +88,12 @@ module PuppetLitmus::Serverspec
59
88
  manifest_file_location
60
89
  end
61
90
 
91
+ # Runs a command against the target system
92
+ #
93
+ # @param command_to_run [String] The command to execute.
94
+ # @param opts [Hash] Alters the behaviour of the command. Valid options are :expect_failures [Boolean] doesnt return an exit code of non-zero if the command failed.
95
+ # @param [Block] his method will yield to a block of code passed by the caller; this can be used for additional validation, etc.
96
+ # @return [Object] A result object from the command.
62
97
  def run_shell(command_to_run, opts = {})
63
98
  inventory_hash = inventory_hash_from_inventory_file
64
99
  target_node_name = ENV['TARGET_HOST']
@@ -66,10 +101,18 @@ module PuppetLitmus::Serverspec
66
101
 
67
102
  raise "shell failed\n`#{command_to_run}`\n======\n#{result}" if result.first['result']['exit_code'] != 0 && opts[:expect_failures] != true
68
103
 
104
+ result = OpenStruct.new(exit_code: result.first['result']['exit_code'],
105
+ stdout: result.first['result']['stdout'],
106
+ stderr: result.first['result']['stderr'])
107
+ yield result if block_given?
69
108
  result
70
109
  end
71
110
 
72
- # Runs a selected task against the target host. Parameters should be passed in with a hash format.
111
+ # Runs a task against the target system.
112
+ #
113
+ # @param task_name [String] The name of the task to run.
114
+ # @param params [Hash] key : value pairs to be passed to the task.
115
+ # @return [Object] A result object from the task.
73
116
  def run_bolt_task(task_name, params = {})
74
117
  config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
75
118
  inventory_hash = inventory_hash_from_inventory_file
@@ -2,5 +2,5 @@
2
2
 
3
3
  # version of this gem
4
4
  module PuppetLitmus
5
- VERSION ||= '0.1.1'
5
+ VERSION ||= '0.2.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet_litmus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-29 00:00:00.000000000 Z
11
+ date: 2019-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bolt
@@ -50,6 +50,26 @@ dependencies:
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: 2.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: tty-spinner
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 0.5.0
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: 1.0.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 0.5.0
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: 1.0.0
53
73
  description: " Providing a simple command line tool for puppet content creators,
54
74
  to enable simple and complex test deployments.\n"
55
75
  email: