puppet_litmus 0.1.1 → 0.2.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.
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: