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.
- checksums.yaml +4 -4
- data/README.md +12 -16
- data/lib/puppet_litmus.rb +0 -20
- data/lib/puppet_litmus/inventory_manipulation.rb +12 -1
- data/lib/puppet_litmus/puppet_helpers.rb +200 -137
- data/lib/puppet_litmus/rake_helper.rb +243 -101
- data/lib/puppet_litmus/rake_tasks.rb +36 -41
- data/lib/puppet_litmus/util.rb +17 -0
- data/lib/puppet_litmus/version.rb +1 -1
- data/spec/lib/puppet_litmus/inventory_manipulation_spec.rb +16 -18
- data/spec/lib/puppet_litmus/puppet_helpers_spec.rb +107 -124
- data/spec/lib/puppet_litmus/rake_helper_spec.rb +77 -27
- data/spec/lib/puppet_litmus/rake_tasks_spec.rb +8 -9
- data/spec/lib/puppet_litmus/util_spec.rb +15 -0
- data/spec/lib/puppet_litmus/version_spec.rb +0 -3
- data/spec/spec_helper.rb +7 -1
- metadata +76 -25
@@ -1,11 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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
|
8
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
61
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
129
|
-
|
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
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
require '
|
173
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
-
|
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['
|
60
|
+
failed_image_message += "=====\n#{result.first['target']}\n#{result.first['value']['_output']}\n#{result.inspect}"
|
57
61
|
else
|
58
|
-
STDOUT.puts "#{result.first['
|
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['
|
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['
|
119
|
-
raise "Failed on #{result['
|
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['
|
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['
|
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
|
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
|
-
|
199
|
-
|
200
|
-
|
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
|
-
|
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
|
-
|
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['
|
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['
|
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?
|