puppet_litmus 0.15.0 → 0.18.2

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.
@@ -1,11 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module PuppetLitmus; end # rubocop:disable Style/Documentation
3
+ require 'bolt_spec/run'
4
+ require 'honeycomb-beeline'
5
+ Honeycomb.configure do |config|
6
+ # override client if no configuration is provided, so that the pesky libhoney warning about lack of configuration is not shown
7
+ unless ENV['HONEYCOMB_WRITEKEY'] && ENV['HONEYCOMB_DATASET']
8
+ config.client = Libhoney::NullClient.new
9
+ end
10
+ end
11
+ process_span = Honeycomb.start_span(name: 'Litmus Testing', serialized_trace: ENV['HTTP_X_HONEYCOMB_TRACE'])
12
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = process_span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
13
+ Honeycomb.add_field_to_trace('litmus.pid', Process.pid)
14
+ if ENV['CI'] == 'true' && ENV['TRAVIS'] == 'true'
15
+ Honeycomb.add_field_to_trace('module_name', ENV['TRAVIS_REPO_SLUG'])
16
+ Honeycomb.add_field_to_trace('ci.provider', 'travis')
17
+ Honeycomb.add_field_to_trace('ci.build_id', ENV['TRAVIS_BUILD_ID'])
18
+ Honeycomb.add_field_to_trace('ci.build_url', ENV['TRAVIS_BUILD_WEB_URL'])
19
+ Honeycomb.add_field_to_trace('ci.job_url', ENV['TRAVIS_JOB_WEB_URL'])
20
+ Honeycomb.add_field_to_trace('ci.commit_message', ENV['TRAVIS_COMMIT_MESSAGE'])
21
+ Honeycomb.add_field_to_trace('ci.sha', ENV['TRAVIS_PULL_REQUEST_SHA'] || ENV['TRAVIS_COMMIT'])
22
+ elsif ENV['CI'] == 'True' && ENV['APPVEYOR'] == 'True'
23
+ Honeycomb.add_field_to_trace('module_name', ENV['APPVEYOR_PROJECT_SLUG'])
24
+ Honeycomb.add_field_to_trace('ci.provider', 'appveyor')
25
+ Honeycomb.add_field_to_trace('ci.build_id', ENV['APPVEYOR_BUILD_ID'])
26
+ Honeycomb.add_field_to_trace('ci.build_url', "https://ci.appveyor.com/project/#{ENV['APPVEYOR_REPO_NAME']}/builds/#{ENV['APPVEYOR_BUILD_ID']}")
27
+ Honeycomb.add_field_to_trace('ci.job_url', "https://ci.appveyor.com/project/#{ENV['APPVEYOR_REPO_NAME']}/build/job/#{ENV['APPVEYOR_JOB_ID']}")
28
+ Honeycomb.add_field_to_trace('ci.commit_message', ENV['APPVEYOR_REPO_COMMIT_MESSAGE'])
29
+ Honeycomb.add_field_to_trace('ci.sha', ENV['APPVEYOR_PULL_REQUEST_HEAD_COMMIT'] || ENV['APPVEYOR_REPO_COMMIT'])
30
+ elsif ENV['GITHUB_ACTIONS'] == 'true'
31
+ Honeycomb.add_field_to_trace('module_name', ENV['GITHUB_REPOSITORY'])
32
+ Honeycomb.add_field_to_trace('ci.provider', 'github')
33
+ Honeycomb.add_field_to_trace('ci.build_id', ENV['GITHUB_RUN_ID'])
34
+ Honeycomb.add_field_to_trace('ci.build_url', "https://github.com/#{ENV['GITHUB_REPOSITORY']}/actions/runs/#{ENV['GITHUB_RUN_ID']}")
35
+ Honeycomb.add_field_to_trace('ci.sha', ENV['GITHUB_SHA'])
36
+ end
37
+ at_exit do
38
+ process_span.send
39
+ end
4
40
 
5
41
  # helper methods for the litmus rake tasks
6
42
  module PuppetLitmus::RakeHelper
7
- DEFAULT_CONFIG_DATA ||= { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }.freeze
8
- VALID_PROVISIONERS ||= %w[abs docker docker_exp vagrant vmpooler].freeze
43
+ # DEFAULT_CONFIG_DATA should be frozen for our safety, but it needs to work around https://github.com/puppetlabs/bolt/pull/1696
44
+ DEFAULT_CONFIG_DATA ||= { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') } # .freeze # rubocop:disable Style/MutableConstant
45
+ SUPPORTED_PROVISIONERS ||= %w[abs docker docker_exp vagrant vmpooler].freeze
9
46
 
10
47
  # Gets a string representing the operating system and version.
11
48
  #
@@ -52,55 +89,41 @@ module PuppetLitmus::RakeHelper
52
89
  # @param command [String] command to execute.
53
90
  # @return [Object] the standard out stream.
54
91
  def run_local_command(command)
55
- require 'open3'
56
- stdout, stderr, status = Open3.capture3(command)
57
- error_message = "Attempted to run\ncommand:'#{command}'\nstdout:#{stdout}\nstderr:#{stderr}"
58
- raise error_message unless status.to_i.zero?
92
+ Honeycomb.start_span(name: 'litmus.run_local_command') do |span|
93
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
94
+ span.add_field('litmus.command', command)
59
95
 
60
- stdout
61
- end
96
+ require 'open3'
97
+ stdout, stderr, status = Open3.capture3(command)
98
+ error_message = "Attempted to run\ncommand:'#{command}'\nstdout:#{stdout}\nstderr:#{stderr}"
62
99
 
63
- # Builds all the modules in a specified module
64
- #
65
- # @param source_folder [String] the folder to get the modules from
66
- # @return [Array] an array of module tar's
67
- def build_modules_in_folder(source_folder)
68
- folder_list = Dir.entries(source_folder).reject { |f| File.directory? f }
69
- module_tars = []
70
- folder_list.each do |folder|
71
- file = File.new(File.join(source_folder, folder))
72
- next if File.symlink?(file)
100
+ raise error_message unless status.to_i.zero?
73
101
 
74
- opts = {}
75
- opts[:module_dir] = file.path
76
- opts[:'target-dir'] = File.join(Dir.pwd, 'pkg')
77
- opts[:force] = true
78
- # remove old build folder if exists, before we build afresh
79
- FileUtils.rm_rf(builder.build_dir) if File.directory?(builder.build_dir)
80
-
81
- # build_module
82
- module_tar = build_module(opts)
83
- module_tars.push(File.new(module_tar))
102
+ stdout
84
103
  end
85
- module_tars
86
104
  end
87
105
 
88
106
  def provision(provisioner, platform, inventory_vars)
89
- require 'bolt_spec/run'
90
- include BoltSpec::Run
107
+ include ::BoltSpec::Run
91
108
  raise "the provision module was not found in #{DEFAULT_CONFIG_DATA['modulepath']}, please amend the .fixtures.yml file" unless
92
109
  File.directory?(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'provision'))
93
110
 
94
- unless VALID_PROVISIONERS.include?(provisioner)
95
- raise "Unknown provisioner '#{provisioner}', try #{VALID_PROVISIONERS.join('/')}"
96
- end
111
+ params = { 'action' => 'provision', 'platform' => platform, 'inventory' => Dir.pwd }
112
+ params['vars'] = inventory_vars unless inventory_vars.nil?
113
+
114
+ Honeycomb.add_field_to_trace('litmus.provisioner', provisioner)
115
+ Honeycomb.start_span(name: 'litmus.provision') do |span|
116
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
117
+ span.add_field('litmus.platform', platform)
118
+ span.add_field('litmus.inventory', params['inventory'])
119
+ span.add_field('litmus.config', DEFAULT_CONFIG_DATA)
97
120
 
98
- params = if inventory_vars.nil?
99
- { 'action' => 'provision', 'platform' => platform, 'inventory' => Dir.pwd }
100
- else
101
- { 'action' => 'provision', 'platform' => platform, 'inventory' => Dir.pwd, 'vars' => inventory_vars }
102
- end
103
- run_task("provision::#{provisioner}", 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
121
+ bolt_result = run_task(provisioner_task(provisioner), 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
122
+ span.add_field('litmus.node_name', bolt_result&.first&.dig('value', 'node_name'))
123
+ raise_bolt_errors(bolt_result, "provisioning of #{platform} failed.")
124
+
125
+ bolt_result
126
+ end
104
127
  end
105
128
 
106
129
  def provision_list(provision_hash, key)
@@ -109,6 +132,8 @@ module PuppetLitmus::RakeHelper
109
132
  # Splat the params into environment variables to pass to the provision task but only in this runspace
110
133
  provision_hash[key]['params']&.each { |k, value| ENV[k.upcase] = value.to_s }
111
134
  results = []
135
+
136
+ Honeycomb.current_span.add_field('litmus.images', provision_hash[key]['images'])
112
137
  provision_hash[key]['images'].each do |image|
113
138
  results << provision(provisioner, image, inventory_vars)
114
139
  end
@@ -116,42 +141,62 @@ module PuppetLitmus::RakeHelper
116
141
  end
117
142
 
118
143
  def tear_down_nodes(targets, inventory_hash)
119
- require 'bolt_spec/run'
120
- include BoltSpec::Run
121
- config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
122
- 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'))
144
+ Honeycomb.start_span(name: 'litmus.tear_down_nodes') do |span|
145
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
146
+ span.add_field('litmus.targets', targets)
123
147
 
124
- results = {}
125
- targets.each do |node_name|
126
- next if node_name == 'litmus_localhost'
148
+ include ::BoltSpec::Run
149
+ config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
150
+ 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'))
127
151
 
128
- result = tear_down(node_name, inventory_hash)
129
- results[node_name] = result unless result == []
152
+ results = {}
153
+ targets.each do |node_name|
154
+ next if node_name == 'litmus_localhost'
155
+
156
+ result = tear_down(node_name, inventory_hash)
157
+ results[node_name] = result unless result == []
158
+ end
159
+ results
130
160
  end
131
- results
132
161
  end
133
162
 
134
163
  def tear_down(node_name, inventory_hash)
135
- # how do we know what provisioner to use
136
- node_facts = facts_from_node(inventory_hash, node_name)
137
- return [] unless VALID_PROVISIONERS.include?(node_facts['provisioner'])
138
-
139
- params = { 'action' => 'tear_down', 'node_name' => node_name, 'inventory' => Dir.pwd }
140
- run_task("provision::#{node_facts['provisioner']}", 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
164
+ Honeycomb.start_span(name: 'litmus.tear_down') do |span|
165
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
166
+ # how do we know what provisioner to use
167
+
168
+ span.add_field('litmus.node_name', node_name)
169
+ add_platform_field(inventory_hash, node_name)
170
+
171
+ params = { 'action' => 'tear_down', 'node_name' => node_name, 'inventory' => Dir.pwd }
172
+ node_facts = facts_from_node(inventory_hash, node_name)
173
+ bolt_result = run_task(provisioner_task(node_facts['provisioner']), 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
174
+ raise_bolt_errors(bolt_result, "tear_down of #{node_name} failed.")
175
+ bolt_result
176
+ end
141
177
  end
142
178
 
143
179
  def install_agent(collection, targets, inventory_hash)
144
- require 'bolt_spec/run'
145
- include BoltSpec::Run
146
- params = if collection.nil?
147
- {}
148
- else
149
- { 'collection' => collection }
150
- end
151
- raise "puppet_agent was not found in #{DEFAULT_CONFIG_DATA['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'puppet_agent'))
152
-
153
- # using boltspec, when the runner is called it changes the inventory_hash dropping the version field. The clone works around this
154
- run_task('puppet_agent::install', targets, params, config: DEFAULT_CONFIG_DATA, inventory: inventory_hash.clone)
180
+ Honeycomb.start_span(name: 'litmus.install_agent') do |span|
181
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
182
+ span.add_field('litmus.collection', collection)
183
+ span.add_field('litmus.targets', targets)
184
+
185
+ include ::BoltSpec::Run
186
+ params = if collection.nil?
187
+ {}
188
+ else
189
+ Honeycomb.current_span.add_field('litmus.collection', collection)
190
+ { 'collection' => collection }
191
+ end
192
+ raise "puppet_agent was not found in #{DEFAULT_CONFIG_DATA['modulepath']}, please amend the .fixtures.yml file" \
193
+ unless File.directory?(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'puppet_agent'))
194
+
195
+ # using boltspec, when the runner is called it changes the inventory_hash dropping the version field. The clone works around this
196
+ bolt_result = run_task('puppet_agent::install', targets, params, config: DEFAULT_CONFIG_DATA, inventory: inventory_hash.clone)
197
+ raise_bolt_errors(bolt_result, 'Installation of agent failed.')
198
+ bolt_result
199
+ end
155
200
  end
156
201
 
157
202
  def configure_path(inventory_hash)
@@ -164,30 +209,72 @@ module PuppetLitmus::RakeHelper
164
209
  results
165
210
  end
166
211
 
167
- def build_module(opts)
168
- # old cli_way
169
- # pdk_build_command = 'bundle exec pdk build --force'
170
- # stdout, stderr, _status = Open3.capture3(pdk_build_command)
171
- # raise "Failed to run 'pdk_build_command',#{stdout} and #{stderr}" if (stderr =~ %r{completed successfully}).nil?
172
- require 'pdk/module/build'
173
- require 'pdk/util'
212
+ # @param opts Hash of options to build the module
213
+ # @param module_dir [String] The path of the module to build. If missing defaults to Dir.pwd
214
+ # @param target_dir [String] The path the module will be built into. The default is <source_dir>/pkg
215
+ # @return [String] The path to the built module
216
+ def build_module(module_dir = nil, target_dir = nil)
217
+ require 'puppet/modulebuilder'
218
+
219
+ source_dir = module_dir || Dir.pwd
220
+ dest_dir = target_dir || File.join(source_dir, 'pkg')
221
+
222
+ builder = Puppet::Modulebuilder::Builder.new(source_dir, dest_dir, nil)
223
+ # Force the metadata to be read. Raises if metadata could not be found
224
+ _metadata = builder.metadata
174
225
 
175
- builder = PDK::Module::Build.new(opts)
176
226
  builder.build
177
227
  end
178
228
 
179
- def install_module(inventory_hash, target_node_name, module_tar)
180
- require 'bolt_spec/run'
181
- include BoltSpec::Run
182
- target_nodes = find_targets(inventory_hash, target_node_name)
183
- target_string = if target_node_name.nil?
184
- 'all'
185
- else
186
- target_node_name
187
- end
188
- run_local_command("bundle exec bolt file upload \"#{module_tar}\" /tmp/#{File.basename(module_tar)} --nodes #{target_string} --inventoryfile inventory.yaml")
189
- install_module_command = "puppet module install /tmp/#{File.basename(module_tar)}"
190
- run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
229
+ def install_module(inventory_hash, target_node_name, module_tar, module_repository = 'https://forgeapi.puppetlabs.com')
230
+ Honeycomb.start_span(name: 'install_module') do |span|
231
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
232
+ span.add_field('litmus.target_node_name', target_node_name)
233
+ span.add_field('litmus.module_tar', module_tar)
234
+
235
+ # make sure the target module is not installed
236
+ # otherwise `puppet module install` might silently skip it
237
+ uninstall_module(inventory_hash.clone, target_node_name, force: true)
238
+
239
+ include ::BoltSpec::Run
240
+
241
+ target_nodes = find_targets(inventory_hash, target_node_name)
242
+ span.add_field('litmus.target_nodes', target_nodes)
243
+ bolt_result = upload_file(module_tar, File.basename(module_tar), target_nodes, options: {}, config: nil, inventory: inventory_hash.clone)
244
+ raise_bolt_errors(bolt_result, 'Failed to upload module.')
245
+
246
+ install_module_command = "puppet module install --module_repository '#{module_repository}' #{File.basename(module_tar)}"
247
+ span.add_field('litmus.install_module_command', install_module_command)
248
+
249
+ bolt_result = run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash.clone)
250
+ raise_bolt_errors(bolt_result, "Installation of package #{File.basename(module_tar)} failed.")
251
+ bolt_result
252
+ end
253
+ end
254
+
255
+ # Builds all the modules in a specified module
256
+ #
257
+ # @param source_folder [String] the folder to get the modules from
258
+ # @return [Array] an array of module tar's
259
+ def build_modules_in_folder(source_folder)
260
+ folder_list = Dir.entries(source_folder).reject { |f| File.directory? f }
261
+ module_tars = []
262
+
263
+ target_dir = File.join(Dir.pwd, 'pkg')
264
+ # remove old build folder if exists, before we build afresh
265
+ FileUtils.rm_rf(target_dir) if File.directory?(target_dir)
266
+
267
+ folder_list.each do |folder|
268
+ folder_handle = Dir.open(File.join(source_folder, folder))
269
+ next if File.symlink?(folder_handle)
270
+
271
+ module_dir = folder_handle.path
272
+
273
+ # build_module
274
+ module_tar = build_module(module_dir, target_dir)
275
+ module_tars.push(File.new(module_tar))
276
+ end
277
+ module_tars
191
278
  end
192
279
 
193
280
  def metadata_module_name
@@ -200,26 +287,81 @@ module PuppetLitmus::RakeHelper
200
287
  metadata['name']
201
288
  end
202
289
 
203
- def uninstall_module(inventory_hash, target_node_name, module_to_remove = nil)
204
- require 'bolt_spec/run'
205
- include BoltSpec::Run
290
+ def uninstall_module(inventory_hash, target_node_name, module_to_remove = nil, **opts)
291
+ include ::BoltSpec::Run
206
292
  module_name = module_to_remove || metadata_module_name
207
293
  target_nodes = find_targets(inventory_hash, target_node_name)
208
294
  install_module_command = "puppet module uninstall #{module_name}"
209
- run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
295
+ install_module_command += ' --force' if opts[:force]
296
+ bolt_result = run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
297
+ # `puppet module uninstall --force` fails if the module is not installed. Ignore errors when force is set
298
+ raise_bolt_errors(bolt_result, "uninstalling #{module_name} failed.") unless opts[:force]
299
+ bolt_result
210
300
  end
211
301
 
212
302
  def check_connectivity?(inventory_hash, target_node_name)
213
- require 'bolt_spec/run'
214
- include BoltSpec::Run
215
- target_nodes = find_targets(inventory_hash, target_node_name)
216
- results = run_command('cd .', target_nodes, config: nil, inventory: inventory_hash)
217
- failed = []
218
- results.each do |result|
219
- failed.push(result['target']) if result['status'] == 'failure'
303
+ Honeycomb.start_span(name: 'litmus.check_connectivity') do |span|
304
+ ENV['HTTP_X_HONEYCOMB_TRACE'] = span.to_trace_header unless ENV['HTTP_X_HONEYCOMB_TRACE']
305
+ # if we're only checking connectivity for a single node
306
+ if target_node_name
307
+ span.add_field('litmus.node_name', target_node_name)
308
+ add_platform_field(inventory_hash, target_node_name)
309
+ end
310
+
311
+ include ::BoltSpec::Run
312
+ target_nodes = find_targets(inventory_hash, target_node_name)
313
+ results = run_command('cd .', target_nodes, config: nil, inventory: inventory_hash)
314
+ span.add_field('litmus.bolt_result', results)
315
+ failed = []
316
+ results.each do |result|
317
+ failed.push(result['target']) if result['status'] == 'failure'
318
+ end
319
+ span.add_field('litmus.connectivity_failed', failed)
320
+ raise "Connectivity has failed on: #{failed}" unless failed.length.zero?
321
+
322
+ true
323
+ end
324
+ end
325
+
326
+ def provisioner_task(provisioner)
327
+ if SUPPORTED_PROVISIONERS.include?(provisioner)
328
+ "provision::#{provisioner}"
329
+ else
330
+ warn "WARNING: Unsuported provisioner '#{provisioner}', try #{SUPPORTED_PROVISIONERS.join('/')}"
331
+ provisioner.to_s
332
+ end
333
+ end
334
+
335
+ # Parse out errors messages in result set returned by Bolt command.
336
+ #
337
+ # @param result_set [Array] result set returned by Bolt command.
338
+ # @return [Hash] Errors grouped by target.
339
+ def check_bolt_errors(result_set)
340
+ errors = {}
341
+ # iterate through each error
342
+ result_set.each do |target_result|
343
+ status = target_result['status']
344
+ # jump to the next one when there is not fail
345
+ next if status != 'failure'
346
+
347
+ target = target_result['target']
348
+ # get some info from error
349
+ errors[target] = target_result['value']['_error']
350
+ end
351
+ errors
352
+ end
353
+
354
+ # Parse out errors messages in result set returned by Bolt command. If there are errors, raise them.
355
+ #
356
+ # @param result_set [Array] result set returned by Bolt command.
357
+ # @param error_msg [String] error message to raise when errors are detected. The actual errors will be appended.
358
+ def raise_bolt_errors(result_set, error_msg)
359
+ errors = check_bolt_errors(result_set)
360
+
361
+ unless errors.empty?
362
+ raise "#{error_msg}\nErrors: #{errors}"
220
363
  end
221
- raise "Connectivity has failed on: #{failed}" unless failed.length.zero?
222
364
 
223
- true
365
+ nil
224
366
  end
225
367
  end
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rake'
4
+
3
5
  namespace :litmus do
6
+ require 'puppet_litmus/inventory_manipulation'
4
7
  require 'puppet_litmus/rake_helper'
8
+ include PuppetLitmus::InventoryManipulation
5
9
  include PuppetLitmus::RakeHelper
6
10
  # Prints all supported OSes from metadata.json file.
7
11
  desc 'print all supported OSes from metadata'
@@ -53,9 +57,9 @@ namespace :litmus do
53
57
  end
54
58
 
55
59
  if result.first['status'] != 'success'
56
- failed_image_message += "=====\n#{result.first['node']}\n#{result.first['result']['_output']}\n#{result.inspect}"
60
+ failed_image_message += "=====\n#{result.first['target']}\n#{result.first['value']['_output']}\n#{result.inspect}"
57
61
  else
58
- STDOUT.puts "#{result.first['result']['node_name']}, #{image}"
62
+ STDOUT.puts "#{result.first['value']['node_name']}, #{image}"
59
63
  end
60
64
  results << result
61
65
  end
@@ -92,7 +96,7 @@ namespace :litmus do
92
96
  else
93
97
  spinner.success
94
98
  end
95
- puts "#{results.first['result']['node_name']}, #{args[:platform]}"
99
+ puts "#{results.first['value']['node_name']}, #{args[:platform]}"
96
100
  end
97
101
 
98
102
  # Install puppet agent on a collection of nodes
@@ -115,11 +119,11 @@ namespace :litmus do
115
119
  results = install_agent(args[:collection], targets, inventory_hash)
116
120
  results.each do |result|
117
121
  if result['status'] != 'success'
118
- command_to_run = "bolt task run puppet_agent::install --targets #{result['node']} --inventoryfile inventory.yaml --modulepath #{DEFAULT_CONFIG_DATA['modulepath']}"
119
- raise "Failed on #{result['node']}\n#{result}\ntry running '#{command_to_run}'"
122
+ command_to_run = "bolt task run puppet_agent::install --targets #{result['target']} --inventoryfile inventory.yaml --modulepath #{DEFAULT_CONFIG_DATA['modulepath']}"
123
+ raise "Failed on #{result['target']}\n#{result}\ntry running '#{command_to_run}'"
120
124
  else
121
125
  # add puppet-agent feature to successful nodes
122
- inventory_hash = add_feature_to_node(inventory_hash, 'puppet-agent', result['node'])
126
+ inventory_hash = add_feature_to_node(inventory_hash, 'puppet-agent', result['target'])
123
127
  end
124
128
  end
125
129
  # update the inventory with the puppet-agent feature set per node
@@ -130,7 +134,7 @@ namespace :litmus do
130
134
 
131
135
  results.each do |result|
132
136
  if result['status'] != 'success'
133
- puts "Failed on #{result['node']}\n#{result}"
137
+ puts "Failed on #{result['target']}\n#{result}"
134
138
  end
135
139
  end
136
140
  end
@@ -167,7 +171,8 @@ namespace :litmus do
167
171
  # @param :source [String] source directory to look in (ignores symlinks) defaults do './spec/fixtures/modules'.
168
172
  # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
169
173
  desc 'install_module - build and install module'
170
- task :install_modules_from_directory, [:source, :target_node_name] do |_task, args|
174
+ task :install_modules_from_directory, [:source, :target_node_name, :module_repository] do |_task, args|
175
+ args.with_defaults(source: nil, target_node_name: nil, module_repository: 'https://forgeapi.puppetlabs.com')
171
176
  inventory_hash = inventory_hash_from_inventory_file
172
177
  target_nodes = find_targets(inventory_hash, args[:target_node_name])
173
178
  if target_nodes.empty?
@@ -181,24 +186,15 @@ namespace :litmus do
181
186
  end
182
187
  raise "Source folder doesnt exist #{source_folder}" unless File.directory?(source_folder)
183
188
 
184
- module_tars = build_modules_in_folder(source_folder)
185
189
  puts 'Building'
186
- module_tars.each do |module_tar|
187
- print "#{File.basename(module_tar)} "
188
- end
190
+ module_tars = build_modules_in_folder(source_folder)
189
191
  require 'bolt_spec/run'
190
192
  include BoltSpec::Run
191
- puts "\nSending"
192
- module_tars.each do |module_tar|
193
- upload_file(module_tar.path, "/tmp/#{File.basename(module_tar)}", target_nodes, options: {}, config: nil, inventory: inventory_hash)
194
- print "#{File.basename(module_tar)} "
195
- end
196
193
  puts "\nInstalling"
197
194
  module_tars.each do |module_tar|
198
- # install_module
199
- install_module_command = "puppet module install --force /tmp/#{File.basename(module_tar)}"
200
- run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
201
- print "#{File.basename(module_tar)} "
195
+ target_nodes.each do |target_node_name|
196
+ install_module(inventory_hash, target_node_name, module_tar, args[:module_repository])
197
+ end
202
198
  end
203
199
  end
204
200
 
@@ -220,7 +216,8 @@ namespace :litmus do
220
216
  #
221
217
  # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
222
218
  desc 'install_module - build and install module'
223
- task :install_module, [:target_node_name] do |_task, args|
219
+ task :install_module, [:target_node_name, :module_repository] do |_task, args|
220
+ args.with_defaults(target_node_name: nil, module_repository: 'https://forgeapi.puppetlabs.com')
224
221
  inventory_hash = inventory_hash_from_inventory_file
225
222
  target_nodes = find_targets(inventory_hash, args[:target_node_name])
226
223
  if target_nodes.empty?
@@ -228,21 +225,13 @@ namespace :litmus do
228
225
  exit 0
229
226
  end
230
227
 
231
- opts = {}
232
- opts[:force] = true
233
- module_tar = build_module(opts)
228
+ module_tar = build_module
234
229
  puts 'Built'
235
230
 
236
231
  # module_tar = Dir.glob('pkg/*.tar.gz').max_by { |f| File.mtime(f) }
237
232
  raise "Unable to find package in 'pkg/*.tar.gz'" if module_tar.nil?
238
233
 
239
- result = install_module(inventory_hash, args[:target_node_name], module_tar)
240
-
241
- raise "Failed trying to run 'puppet module install /tmp/#{File.basename(module_tar)}' against inventory." unless result.is_a?(Array)
242
-
243
- result.each do |node|
244
- puts "#{node['node']} failed #{node['result']}" if node['status'] != 'success'
245
- end
234
+ install_module(inventory_hash, args[:target_node_name], module_tar, args[:module_repository])
246
235
 
247
236
  puts 'Installed'
248
237
  end
@@ -252,11 +241,12 @@ namespace :litmus do
252
241
  # @param :key [String] key that maps to a value for a provisioner and an image to be used for each OS provisioned.
253
242
  # @param :collection [String] parameters to pass to the puppet agent install command.
254
243
  desc 'provision_install - provision a list of machines, install an agent, and the module.'
255
- task :provision_install, [:key, :collection] do |_task, args|
244
+ task :provision_install, [:key, :collection, :module_repository] do |_task, args|
245
+ args.with_defaults(module_repository: 'https://forgeapi.puppetlabs.com')
256
246
  Rake::Task['spec_prep'].invoke
257
247
  Rake::Task['litmus:provision_list'].invoke(args[:key])
258
248
  Rake::Task['litmus:install_agent'].invoke(args[:collection])
259
- Rake::Task['litmus:install_module'].invoke
249
+ Rake::Task['litmus:install_module'].invoke(nil, args[:module_repository])
260
250
  end
261
251
 
262
252
  # Decommissions test machines.
@@ -275,7 +265,7 @@ namespace :litmus do
275
265
  results = tear_down_nodes(targets, inventory_hash)
276
266
  results.each do |node, result|
277
267
  if result.first['status'] != 'success'
278
- bad_results << "#{node}, #{result.first['result']['_error']['msg']}"
268
+ bad_results << "#{node}, #{result.first['value']['_error']['msg']}"
279
269
  else
280
270
  puts "#{node}: #{result.first['status']}"
281
271
  end
@@ -306,7 +296,7 @@ namespace :litmus do
306
296
  raise "Failed trying to run 'puppet module uninstall #{module_name}' against inventory." unless result.is_a?(Array)
307
297
 
308
298
  result.each do |node|
309
- puts "#{node['node']} failed #{node['result']}" if node['status'] != 'success'
299
+ puts "#{node['target']} failed #{node['value']}" if node['status'] != 'success'
310
300
  end
311
301
 
312
302
  puts 'Uninstalled'
@@ -316,16 +306,15 @@ namespace :litmus do
316
306
  #
317
307
  # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
318
308
  desc 'reinstall_module - reinstall module'
319
- task :reinstall_module, [:target_node_name] do |_task, args|
309
+ task :reinstall_module, [:target_node_name, :module_repository] do |_task, args|
310
+ args.with_defaults(target_node_name: nil, module_repository: 'https://forgeapi.puppetlabs.com')
320
311
  Rake::Task['litmus:uninstall_module'].invoke(args[:target_node_name])
321
- Rake::Task['litmus:install_module'].invoke(args[:target_node_name])
312
+ Rake::Task['litmus:install_module'].invoke(args[:target_node_name], args[:module_repository])
322
313
  end
323
314
 
324
315
  namespace :acceptance do
325
316
  require 'rspec/core/rake_task'
326
317
  if File.file?('inventory.yaml')
327
- require 'puppet_litmus/inventory_manipulation'
328
- include PuppetLitmus::InventoryManipulation
329
318
  inventory_hash = inventory_hash_from_inventory_file
330
319
  targets = find_targets(inventory_hash, nil)
331
320
 
@@ -339,7 +328,7 @@ namespace :litmus do
339
328
  payloads = []
340
329
  # Generate list of targets to provision
341
330
  targets.each do |target|
342
- test = 'bundle exec rspec ./spec/acceptance --format progress'
331
+ test = 'bundle exec rspec ./spec/acceptance --format progress --require rspec_honeycomb_formatter --format RSpecHoneycombFormatter'
343
332
  title = "#{target}, #{facts_from_node(inventory_hash, target)['platform']}"
344
333
  options = {
345
334
  env: {
@@ -365,7 +354,12 @@ namespace :litmus do
365
354
 
366
355
  require 'parallel'
367
356
  results = Parallel.map(payloads) do |title, test, options|
357
+ # avoid sending the parent process' main span in the sub-processes
358
+ # https://www.ruby-forum.com/t/at-exit-inherited-across-fork/122473/2
359
+ at_exit { exit! }
360
+
368
361
  env = options[:env].nil? ? {} : options[:env]
362
+ env['HTTP_X_HONEYCOMB_TRACE'] = Honeycomb.current_span.to_trace_header
369
363
  stdout, stderr, status = Open3.capture3(env, test)
370
364
  ["\n================\n#{title}\n", stdout, stderr, status]
371
365
  end
@@ -383,6 +377,7 @@ namespace :litmus do
383
377
  spinners = TTY::Spinner::Multi.new("[:spinner] Running against #{targets.size} targets.")
384
378
  payloads.each do |title, test, options|
385
379
  env = options[:env].nil? ? {} : options[:env]
380
+ env['HTTP_X_HONEYCOMB_TRACE'] = Honeycomb.current_span.to_trace_header
386
381
  spinners.register("[:spinner] #{title}") do |sp|
387
382
  stdout, stderr, status = Open3.capture3(env, test)
388
383
  if status.to_i.zero?