puppet_litmus 0.15.0 → 0.18.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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?