puppet_litmus 0.19.0 → 0.23.1
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/exe/matrix_from_metadata +43 -7
- data/lib/puppet_litmus/inventory_manipulation.rb +7 -6
- data/lib/puppet_litmus/puppet_helpers.rb +24 -13
- data/lib/puppet_litmus/rake_helper.rb +91 -16
- data/lib/puppet_litmus/rake_tasks.rb +74 -66
- data/lib/puppet_litmus/version.rb +1 -1
- data/spec/lib/puppet_litmus/{version_spec.rb → puppet_litmus_version_spec.rb} +0 -0
- data/spec/lib/puppet_litmus/rake_helper_spec.rb +36 -0
- data/spec/lib/puppet_litmus/rake_tasks_spec.rb +6 -0
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11d83a8c9bc28bddfab1549c27e41514cbab10e4e942b1bceadf474bb7ab2866
|
4
|
+
data.tar.gz: e699d388947cb532e2f52a64f3f393da291140cc68efe0f8149b5dea3d8df29b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a33d9d98831af21eeadc21971fc48c1d27f50270e20c5daf267340b1d811bfcb1f3860e8fcd5181a52e58f3f28d068bb100ae18f425a60be98f54ac61b4fb063
|
7
|
+
data.tar.gz: ac37e3be71bf832cc286cad40299eab785c6c52ceb14a3a1bdb7952b51f775bf78b7c7b66298320e3bac081835f3e51083230c7d1cc773e3ee2ede5c7f8ceb96
|
data/exe/matrix_from_metadata
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
# this script creates a build matrix for github actions from the claimed supported platforms in metadata.json
|
4
|
+
# this script creates a build matrix for github actions from the claimed supported platforms and puppet versions in metadata.json
|
5
5
|
|
6
6
|
require 'json'
|
7
7
|
|
8
8
|
IMAGE_TABLE = {
|
9
|
-
'RedHat-6' => 'rhel-6',
|
10
9
|
'RedHat-7' => 'rhel-7',
|
11
10
|
'RedHat-8' => 'rhel-8',
|
12
11
|
'SLES-12' => 'sles-12',
|
@@ -33,16 +32,21 @@ DOCKER_PLATFORMS = [
|
|
33
32
|
'Ubuntu-20.04',
|
34
33
|
].freeze
|
35
34
|
|
35
|
+
# This table uses the latest version in each collection for accurate
|
36
|
+
# comparison when evaluating puppet requirements from the metadata
|
37
|
+
COLLECTION_TABLE = {
|
38
|
+
'5.5.22' => 'puppet5',
|
39
|
+
'6.19.1' => 'puppet6-nightly',
|
40
|
+
'7.0.0' => 'puppet7-nightly',
|
41
|
+
}.freeze
|
42
|
+
|
36
43
|
matrix = {
|
37
44
|
platform: [],
|
38
|
-
collection:
|
39
|
-
puppet5
|
40
|
-
puppet6
|
41
|
-
puppet7-nightly
|
42
|
-
],
|
45
|
+
collection: [],
|
43
46
|
}
|
44
47
|
|
45
48
|
metadata = JSON.parse(File.read('metadata.json'))
|
49
|
+
# Set platforms based on declared operating system support
|
46
50
|
metadata['operatingsystem_support'].sort_by { |a| a['operatingsystem'] }.each do |sup|
|
47
51
|
os = sup['operatingsystem']
|
48
52
|
sup['operatingsystemrelease'].sort_by { |a| a.to_i }.each do |ver|
|
@@ -57,6 +61,38 @@ metadata['operatingsystem_support'].sort_by { |a| a['operatingsystem'] }.each do
|
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
64
|
+
# Set collections based on puppet version requirements
|
65
|
+
if metadata.key?('requirements') && metadata['requirements'].length.positive?
|
66
|
+
metadata['requirements'].each do |req|
|
67
|
+
next unless req.key?('name') && req.key?('version_requirement') && req['name'] == 'puppet'
|
68
|
+
|
69
|
+
ver_regexp = %r{^([>=<]{1,2})\s*([\d.]+)\s+([>=<]{1,2})\s*([\d.]+)$}
|
70
|
+
match = ver_regexp.match(req['version_requirement'])
|
71
|
+
if match.nil?
|
72
|
+
puts "::warning::Didn't recognize version_requirement '#{req['version_requirement']}'"
|
73
|
+
break
|
74
|
+
end
|
75
|
+
|
76
|
+
cmp_one, ver_one, cmp_two, ver_two = match.captures
|
77
|
+
reqs = ["#{cmp_one} #{ver_one}", "#{cmp_two} #{ver_two}"]
|
78
|
+
|
79
|
+
COLLECTION_TABLE.each do |key, val|
|
80
|
+
if Gem::Requirement.create(reqs).satisfied_by?(Gem::Version.new(key))
|
81
|
+
matrix[:collection] << val
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Set to defaults (all collections) if no matches are found
|
88
|
+
if matrix[:collection].empty?
|
89
|
+
matrix[:collection] = COLLECTION_TABLE.values
|
90
|
+
end
|
91
|
+
|
92
|
+
# Just to make sure there aren't any duplicates
|
93
|
+
matrix[:platform] = matrix[:platform].uniq.sort
|
94
|
+
matrix[:collection] = matrix[:collection].uniq.sort
|
95
|
+
|
60
96
|
puts "::set-output name=matrix::#{JSON.generate(matrix)}"
|
61
97
|
|
62
98
|
puts "Created matrix with #{matrix[:platform].length * matrix[:collection].length} cells."
|
@@ -17,10 +17,7 @@ module PuppetLitmus::InventoryManipulation
|
|
17
17
|
end
|
18
18
|
raise "There is no inventory file at '#{inventory_full_path}'." unless File.exist?(inventory_full_path)
|
19
19
|
|
20
|
-
|
21
|
-
raise "Inventory file is incompatible (version 2 and up). Try the 'bolt project migrate' command." if inventory_hash['version'].nil? || (inventory_hash['version'] < 2)
|
22
|
-
|
23
|
-
inventory_hash
|
20
|
+
YAML.load_file(inventory_full_path)
|
24
21
|
end
|
25
22
|
|
26
23
|
# Provide a default hash for executing against localhost
|
@@ -28,7 +25,6 @@ module PuppetLitmus::InventoryManipulation
|
|
28
25
|
# @return [Hash] inventory.yaml hash containing only an entry for localhost
|
29
26
|
def localhost_inventory_hash
|
30
27
|
{
|
31
|
-
'version' => 2,
|
32
28
|
'groups' => [
|
33
29
|
{
|
34
30
|
'name' => 'local',
|
@@ -262,7 +258,12 @@ module PuppetLitmus::InventoryManipulation
|
|
262
258
|
# @param inventory_hash [Hash] hash of the inventory.yaml file
|
263
259
|
# @param node_name [String] node of nodes to limit the search for the node_name in
|
264
260
|
def add_platform_field(inventory_hash, node_name)
|
265
|
-
facts =
|
261
|
+
facts = begin
|
262
|
+
facts_from_node(inventory_hash, node_name)
|
263
|
+
rescue StandardError => e
|
264
|
+
warn e
|
265
|
+
{}
|
266
|
+
end
|
266
267
|
Honeycomb.current_span.add_field('litmus.platform', facts&.dig('platform'))
|
267
268
|
end
|
268
269
|
end
|
@@ -9,9 +9,9 @@ module PuppetLitmus::PuppetHelpers
|
|
9
9
|
# @return [Boolean] The result of the 2 apply manifests.
|
10
10
|
def idempotent_apply(manifest)
|
11
11
|
Honeycomb.start_span(name: 'litmus.idempotent_apply') do |span|
|
12
|
-
ENV['
|
12
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
13
13
|
manifest_file_location = create_manifest_file(manifest)
|
14
|
-
apply_manifest(nil,
|
14
|
+
apply_manifest(nil, catch_failures: true, manifest_file_location: manifest_file_location)
|
15
15
|
apply_manifest(nil, catch_changes: true, manifest_file_location: manifest_file_location)
|
16
16
|
end
|
17
17
|
end
|
@@ -30,7 +30,7 @@ module PuppetLitmus::PuppetHelpers
|
|
30
30
|
# :catch_failures [Boolean] (false) We're after only complete success so allow exit codes 0 and 2 only.
|
31
31
|
# :expect_failures [Boolean] (false) We're after failures specifically so allow exit codes 1, 4, and 6 only.
|
32
32
|
# :manifest_file_location [Path] The place on the target system.
|
33
|
-
# :hiera_config [Path] The path to the hiera.yaml configuration on the
|
33
|
+
# :hiera_config [Path] The path to the hiera.yaml configuration on the target.
|
34
34
|
# :prefix_command [String] prefixes the puppet apply command; eg "export LANGUAGE='ja'".
|
35
35
|
# :trace [Boolean] run puppet apply with the trace flag (defaults to `true`).
|
36
36
|
# :debug [Boolean] run puppet apply with the debug flag.
|
@@ -39,7 +39,7 @@ module PuppetLitmus::PuppetHelpers
|
|
39
39
|
# @return [Object] A result object from the apply.
|
40
40
|
def apply_manifest(manifest, opts = {})
|
41
41
|
Honeycomb.start_span(name: 'litmus.apply_manifest') do |span|
|
42
|
-
ENV['
|
42
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
43
43
|
span.add_field('litmus.manifest', manifest)
|
44
44
|
span.add_field('litmus.opts', opts)
|
45
45
|
|
@@ -83,11 +83,22 @@ module PuppetLitmus::PuppetHelpers
|
|
83
83
|
command_to_run += ' --noop' if !opts[:noop].nil? && (opts[:noop] == true)
|
84
84
|
command_to_run += ' --detailed-exitcodes' if use_detailed_exit_codes == true
|
85
85
|
|
86
|
-
span.add_field('litmus.command_to_run', command_to_run)
|
87
86
|
span.add_field('litmus.target_node_name', target_node_name)
|
88
|
-
bolt_result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
|
89
|
-
span.add_field('litmus.bolt_result', bolt_result)
|
90
87
|
|
88
|
+
if os[:family] == 'windows'
|
89
|
+
# IAC-1365 - Workaround for BOLT-1535 and bolt issue #1650
|
90
|
+
command_to_run = "try { #{command_to_run}; exit $LASTEXITCODE } catch { write-error $_ ; exit 1 }"
|
91
|
+
span.add_field('litmus.command_to_run', command_to_run)
|
92
|
+
bolt_result = Tempfile.open(['temp', '.ps1']) do |script|
|
93
|
+
script.write(command_to_run)
|
94
|
+
script.close
|
95
|
+
run_script(script.path, target_node_name, [], options: {}, config: nil, inventory: inventory_hash)
|
96
|
+
end
|
97
|
+
else
|
98
|
+
span.add_field('litmus.command_to_run', command_to_run)
|
99
|
+
bolt_result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
|
100
|
+
end
|
101
|
+
span.add_field('litmus.bolt_result', bolt_result)
|
91
102
|
result = OpenStruct.new(exit_code: bolt_result.first['value']['exit_code'],
|
92
103
|
stdout: bolt_result.first['value']['stdout'],
|
93
104
|
stderr: bolt_result.first['value']['stderr'])
|
@@ -117,7 +128,7 @@ module PuppetLitmus::PuppetHelpers
|
|
117
128
|
# @return [String] The path to the location of the manifest.
|
118
129
|
def create_manifest_file(manifest)
|
119
130
|
Honeycomb.start_span(name: 'litmus.create_manifest_file') do |span|
|
120
|
-
ENV['
|
131
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
121
132
|
span.add_field('litmus.manifest', manifest)
|
122
133
|
|
123
134
|
require 'tmpdir'
|
@@ -154,7 +165,7 @@ module PuppetLitmus::PuppetHelpers
|
|
154
165
|
# @return [Bool] Success. The file was succesfully writtne on the target.
|
155
166
|
def write_file(content, destination)
|
156
167
|
Honeycomb.start_span(name: 'litmus.write_file') do |span|
|
157
|
-
ENV['
|
168
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
158
169
|
span.add_field('litmus.destination', destination)
|
159
170
|
|
160
171
|
require 'tmpdir'
|
@@ -191,7 +202,7 @@ module PuppetLitmus::PuppetHelpers
|
|
191
202
|
# @return [Object] A result object from the command.
|
192
203
|
def run_shell(command_to_run, opts = {})
|
193
204
|
Honeycomb.start_span(name: 'litmus.run_shell') do |span|
|
194
|
-
ENV['
|
205
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
195
206
|
span.add_field('litmus.command_to_run', command_to_run)
|
196
207
|
span.add_field('litmus.opts', opts)
|
197
208
|
|
@@ -228,7 +239,7 @@ module PuppetLitmus::PuppetHelpers
|
|
228
239
|
# @return [Object] A result object from the command.
|
229
240
|
def bolt_upload_file(source, destination, opts = {}, options = {})
|
230
241
|
Honeycomb.start_span(name: 'litmus.bolt_upload_file') do |span|
|
231
|
-
ENV['
|
242
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
232
243
|
span.add_field('litmus.source', source)
|
233
244
|
span.add_field('litmus.destination', destination)
|
234
245
|
span.add_field('litmus.opts', opts)
|
@@ -280,7 +291,7 @@ module PuppetLitmus::PuppetHelpers
|
|
280
291
|
# @return [Object] A result object from the task.The values available are stdout, stderr and result.
|
281
292
|
def run_bolt_task(task_name, params = {}, opts = {})
|
282
293
|
Honeycomb.start_span(name: 'litmus.run_task') do |span|
|
283
|
-
ENV['
|
294
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
284
295
|
span.add_field('litmus.task_name', task_name)
|
285
296
|
span.add_field('litmus.params', params)
|
286
297
|
span.add_field('litmus.opts', opts)
|
@@ -348,7 +359,7 @@ module PuppetLitmus::PuppetHelpers
|
|
348
359
|
# @return [Object] A result object from the script run.
|
349
360
|
def bolt_run_script(script, opts = {}, arguments: [])
|
350
361
|
Honeycomb.start_span(name: 'litmus.bolt_run_script') do |span|
|
351
|
-
ENV['
|
362
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
352
363
|
span.add_field('litmus.script', script)
|
353
364
|
span.add_field('litmus.opts', opts)
|
354
365
|
span.add_field('litmus.arguments', arguments)
|
@@ -9,8 +9,8 @@ Honeycomb.configure do |config|
|
|
9
9
|
config.client = Libhoney::NullClient.new
|
10
10
|
end
|
11
11
|
end
|
12
|
-
process_span = Honeycomb.start_span(name: "litmus: #{([$PROGRAM_NAME] + ($ARGV || [])).join(' ')}", serialized_trace: ENV['
|
13
|
-
ENV['
|
12
|
+
process_span = Honeycomb.start_span(name: "litmus: #{([$PROGRAM_NAME] + ($ARGV || [])).join(' ')}", serialized_trace: ENV['HONEYCOMB_TRACE'])
|
13
|
+
ENV['HONEYCOMB_TRACE'] = process_span.to_trace_header
|
14
14
|
Honeycomb.add_field_to_trace('litmus.pid', Process.pid)
|
15
15
|
if defined? PuppetLitmus::VERSION
|
16
16
|
Honeycomb.add_field_to_trace('litmus.version', PuppetLitmus::VERSION)
|
@@ -41,6 +41,13 @@ elsif ENV['GITHUB_ACTIONS'] == 'true'
|
|
41
41
|
Honeycomb.add_field_to_trace('ci.sha', ENV['GITHUB_SHA'])
|
42
42
|
end
|
43
43
|
at_exit do
|
44
|
+
if $ERROR_INFO.is_a?(SystemExit)
|
45
|
+
process_span.add_field('process.exit_code', $ERROR_INFO.status)
|
46
|
+
elsif $ERROR_INFO
|
47
|
+
process_span.add_field('process.exit_code', $ERROR_INFO.class.name)
|
48
|
+
else
|
49
|
+
process_span.add_field('process.exit_code', 'unknown')
|
50
|
+
end
|
44
51
|
process_span.send
|
45
52
|
end
|
46
53
|
|
@@ -96,7 +103,7 @@ module PuppetLitmus::RakeHelper
|
|
96
103
|
# @return [Object] the standard out stream.
|
97
104
|
def run_local_command(command)
|
98
105
|
Honeycomb.start_span(name: 'litmus.run_local_command') do |span|
|
99
|
-
ENV['
|
106
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
100
107
|
span.add_field('litmus.command', command)
|
101
108
|
|
102
109
|
require 'open3'
|
@@ -119,13 +126,18 @@ module PuppetLitmus::RakeHelper
|
|
119
126
|
|
120
127
|
Honeycomb.add_field_to_trace('litmus.provisioner', provisioner)
|
121
128
|
Honeycomb.start_span(name: 'litmus.provision') do |span|
|
122
|
-
ENV['
|
129
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
123
130
|
span.add_field('litmus.platform', platform)
|
124
|
-
|
131
|
+
|
132
|
+
task_name = provisioner_task(provisioner)
|
133
|
+
span.add_field('litmus.task_name', task_name)
|
134
|
+
span.add_field('litmus.params', params)
|
125
135
|
span.add_field('litmus.config', DEFAULT_CONFIG_DATA)
|
126
136
|
|
127
|
-
bolt_result = run_task(
|
137
|
+
bolt_result = run_task(task_name, 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
|
138
|
+
span.add_field('litmus.result', bolt_result)
|
128
139
|
span.add_field('litmus.node_name', bolt_result&.first&.dig('value', 'node_name'))
|
140
|
+
|
129
141
|
raise_bolt_errors(bolt_result, "provisioning of #{platform} failed.")
|
130
142
|
|
131
143
|
bolt_result
|
@@ -148,7 +160,7 @@ module PuppetLitmus::RakeHelper
|
|
148
160
|
|
149
161
|
def tear_down_nodes(targets, inventory_hash)
|
150
162
|
Honeycomb.start_span(name: 'litmus.tear_down_nodes') do |span|
|
151
|
-
ENV['
|
163
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
152
164
|
span.add_field('litmus.targets', targets)
|
153
165
|
|
154
166
|
include ::BoltSpec::Run
|
@@ -160,6 +172,18 @@ module PuppetLitmus::RakeHelper
|
|
160
172
|
next if node_name == 'litmus_localhost'
|
161
173
|
|
162
174
|
result = tear_down(node_name, inventory_hash)
|
175
|
+
# Some provisioners tear_down targets that were created as a batch job.
|
176
|
+
# These provisioners should return the list of additional targets
|
177
|
+
# removed so that we do not attempt to process them.
|
178
|
+
if result != [] && result[0]['value'].key?('removed')
|
179
|
+
removed_targets = result[0]['value']['removed']
|
180
|
+
result[0]['value'].delete('removed')
|
181
|
+
removed_targets.each do |removed_target|
|
182
|
+
targets.delete(removed_target)
|
183
|
+
results[removed_target] = result
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
163
187
|
results[node_name] = result unless result == []
|
164
188
|
end
|
165
189
|
results
|
@@ -168,7 +192,7 @@ module PuppetLitmus::RakeHelper
|
|
168
192
|
|
169
193
|
def tear_down(node_name, inventory_hash)
|
170
194
|
Honeycomb.start_span(name: 'litmus.tear_down') do |span|
|
171
|
-
ENV['
|
195
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
172
196
|
# how do we know what provisioner to use
|
173
197
|
|
174
198
|
span.add_field('litmus.node_name', node_name)
|
@@ -184,7 +208,7 @@ module PuppetLitmus::RakeHelper
|
|
184
208
|
|
185
209
|
def install_agent(collection, targets, inventory_hash)
|
186
210
|
Honeycomb.start_span(name: 'litmus.install_agent') do |span|
|
187
|
-
ENV['
|
211
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
188
212
|
span.add_field('litmus.collection', collection)
|
189
213
|
span.add_field('litmus.targets', targets)
|
190
214
|
|
@@ -192,7 +216,6 @@ module PuppetLitmus::RakeHelper
|
|
192
216
|
params = if collection.nil?
|
193
217
|
{}
|
194
218
|
else
|
195
|
-
Honeycomb.current_span.add_field('litmus.collection', collection)
|
196
219
|
{ 'collection' => collection }
|
197
220
|
end
|
198
221
|
raise "puppet_agent was not found in #{DEFAULT_CONFIG_DATA['modulepath']}, please amend the .fixtures.yml file" \
|
@@ -277,7 +300,7 @@ module PuppetLitmus::RakeHelper
|
|
277
300
|
# @return a bolt result
|
278
301
|
def install_module(inventory_hash, target_node_name, module_tar, module_repository = nil, ignore_dependencies = false) # rubocop:disable Style/OptionalBooleanParameter
|
279
302
|
Honeycomb.start_span(name: 'install_module') do |span|
|
280
|
-
ENV['
|
303
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
281
304
|
span.add_field('litmus.target_node_name', target_node_name)
|
282
305
|
span.add_field('litmus.module_tar', module_tar)
|
283
306
|
|
@@ -333,24 +356,30 @@ module PuppetLitmus::RakeHelper
|
|
333
356
|
|
334
357
|
def check_connectivity?(inventory_hash, target_node_name)
|
335
358
|
Honeycomb.start_span(name: 'litmus.check_connectivity') do |span|
|
336
|
-
ENV['
|
359
|
+
ENV['HONEYCOMB_TRACE'] = span.to_trace_header
|
337
360
|
# if we're only checking connectivity for a single node
|
338
361
|
if target_node_name
|
339
|
-
span.add_field('litmus.
|
362
|
+
span.add_field('litmus.target_node_name', target_node_name)
|
340
363
|
add_platform_field(inventory_hash, target_node_name)
|
341
364
|
end
|
342
365
|
|
343
366
|
include ::BoltSpec::Run
|
344
367
|
target_nodes = find_targets(inventory_hash, target_node_name)
|
368
|
+
puts "Checking connectivity for #{target_nodes.inspect}"
|
369
|
+
span.add_field('litmus.target_nodes', target_nodes)
|
370
|
+
|
345
371
|
results = run_command('cd .', target_nodes, config: nil, inventory: inventory_hash)
|
346
372
|
span.add_field('litmus.bolt_result', results)
|
347
373
|
failed = []
|
348
|
-
results.each do |result|
|
349
|
-
|
374
|
+
results.reject { |r| r['status'] == 'success' }.each do |result|
|
375
|
+
puts "Failure connecting to #{result['target']}:\n#{result.inspect}"
|
376
|
+
failed.push(result['target'])
|
350
377
|
end
|
351
|
-
span.add_field('litmus.
|
378
|
+
span.add_field('litmus.connectivity_success', results.select { |r| r['status'] == 'success' })
|
379
|
+
span.add_field('litmus.connectivity_failure', results.reject { |r| r['status'] == 'success' })
|
352
380
|
raise "Connectivity has failed on: #{failed}" unless failed.length.zero?
|
353
381
|
|
382
|
+
puts 'Connectivity check PASSED.'
|
354
383
|
true
|
355
384
|
end
|
356
385
|
end
|
@@ -397,4 +426,50 @@ module PuppetLitmus::RakeHelper
|
|
397
426
|
|
398
427
|
nil
|
399
428
|
end
|
429
|
+
|
430
|
+
def start_spinner(message)
|
431
|
+
if (ENV['CI'] || '').downcase == 'true'
|
432
|
+
puts message
|
433
|
+
spinner = Thread.new do
|
434
|
+
# CI systems are strange beasts, we only output a '.' every wee while to keep the terminal alive.
|
435
|
+
loop do
|
436
|
+
printf '.'
|
437
|
+
sleep(10)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
else
|
441
|
+
require 'tty-spinner'
|
442
|
+
spinner = TTY::Spinner.new("[:spinner] #{message}")
|
443
|
+
spinner.auto_spin
|
444
|
+
end
|
445
|
+
spinner
|
446
|
+
end
|
447
|
+
|
448
|
+
def stop_spinner(spinner)
|
449
|
+
if (ENV['CI'] || '').downcase == 'true'
|
450
|
+
Thread.kill(spinner)
|
451
|
+
else
|
452
|
+
spinner.success
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
require 'retryable'
|
457
|
+
|
458
|
+
Retryable.configure do |config|
|
459
|
+
config.sleep = ->(n) { (1.5**n) + Random.rand(0.5) }
|
460
|
+
# config.log_method = ->(retries, exception) do
|
461
|
+
# Logger.new($stdout).debug("[Attempt ##{retries}] Retrying because [#{exception.class} - #{exception.message}]: #{exception.backtrace.first(5).join(' | ')}")
|
462
|
+
# end
|
463
|
+
end
|
464
|
+
|
465
|
+
class LitmusTimeoutError < StandardError; end
|
466
|
+
|
467
|
+
def with_retries(options: { tries: Float::INFINITY }, max_wait_minutes: 8)
|
468
|
+
stop = Time.now + (max_wait_minutes * 60)
|
469
|
+
Retryable.retryable(options.merge(not: [LitmusTimeoutError])) do
|
470
|
+
raise LitmusTimeoutError if Time.now > stop
|
471
|
+
|
472
|
+
yield
|
473
|
+
end
|
474
|
+
end
|
400
475
|
end
|
@@ -33,35 +33,35 @@ namespace :litmus do
|
|
33
33
|
inventory_vars = provision_hash[args[:key]]['vars']
|
34
34
|
# Splat the params into environment variables to pass to the provision task but only in this runspace
|
35
35
|
provision_hash[args[:key]]['params']&.each { |k, value| ENV[k.upcase] = value.to_s }
|
36
|
-
results = []
|
37
36
|
failed_image_message = ''
|
38
|
-
provision_hash[args[:key]]['images'].
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
else
|
47
|
-
require 'tty-spinner'
|
48
|
-
spinner = TTY::Spinner.new("Provisioning #{image} using #{provisioner} provisioner.[:spinner]")
|
49
|
-
spinner.auto_spin
|
50
|
-
end
|
51
|
-
result = provision(provisioner, image, inventory_vars)
|
52
|
-
|
53
|
-
if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
|
54
|
-
Thread.kill(progress)
|
55
|
-
else
|
56
|
-
spinner.success
|
37
|
+
if provision_hash[args[:key]]['images'].instance_of?(Hash)
|
38
|
+
begin
|
39
|
+
spinner = start_spinner("Provisioning multiple images using #{provisioner} provisioner.")
|
40
|
+
result = provision(provisioner, provision_hash[args[:key]]['images'], inventory_vars)
|
41
|
+
ensure
|
42
|
+
stop_spinner(spinner)
|
57
43
|
end
|
58
44
|
|
59
45
|
if result.first['status'] != 'success'
|
60
46
|
failed_image_message += "=====\n#{result.first['target']}\n#{result.first['value']['_output']}\n#{result.inspect}"
|
61
47
|
else
|
62
|
-
$stdout.puts
|
48
|
+
$stdout.puts 'Success'
|
49
|
+
end
|
50
|
+
else
|
51
|
+
provision_hash[args[:key]]['images'].each do |image|
|
52
|
+
begin
|
53
|
+
spinner = start_spinner("Provisioning #{image} using #{provisioner} provisioner.")
|
54
|
+
result = provision(provisioner, image, inventory_vars)
|
55
|
+
ensure
|
56
|
+
stop_spinner(spinner)
|
57
|
+
end
|
58
|
+
|
59
|
+
if result.first['status'] != 'success'
|
60
|
+
failed_image_message += "=====\n#{result.first['target']}\n#{result.first['value']['_output']}\n#{result.inspect}"
|
61
|
+
else
|
62
|
+
$stdout.puts "#{result.first['value']['node_name']}, #{image}"
|
63
|
+
end
|
63
64
|
end
|
64
|
-
results << result
|
65
65
|
end
|
66
66
|
|
67
67
|
raise "Failed to provision with '#{provisioner}'\n #{failed_image_message}" unless failed_image_message.empty?
|
@@ -74,28 +74,35 @@ namespace :litmus do
|
|
74
74
|
desc 'provision a test system using the given provisioner and platform name. See the puppetlabs-provision module tasks for more documentation'
|
75
75
|
task :provision, [:provisioner, :platform, :inventory_vars] do |_task, args|
|
76
76
|
Rake::Task['spec_prep'].invoke
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
|
78
|
+
begin
|
79
|
+
spinner = start_spinner("Provisioning #{args[:platform]} using #{args[:provisioner]} provisioner.")
|
80
|
+
|
81
|
+
results = provision(args[:provisioner], args[:platform], args[:inventory_vars])
|
82
|
+
|
83
|
+
unless results.first['status'] == 'success'
|
84
|
+
raise "Failed provisioning #{args[:platform]} using #{args[:provisioner]}\n#{results.first}"
|
85
|
+
end
|
86
|
+
|
87
|
+
puts "Successfully provisioned #{args[:platform]} using #{args[:provisioner]}\n"
|
88
|
+
|
89
|
+
target_names = if results.first['value']['node']
|
90
|
+
[results.first['value']['node']['uri']]
|
91
|
+
else
|
92
|
+
results.first['value']['target_names'] || [] # provision_service multi-node provisioning
|
93
|
+
end
|
94
|
+
target_names.each do |target|
|
95
|
+
Honeycomb.start_span(name: 'litmus.provision.check_connectivity') do |span|
|
96
|
+
span.add_field('target_name', target)
|
97
|
+
with_retries do
|
98
|
+
check_connectivity?(inventory_hash_from_inventory_file, target)
|
99
|
+
end
|
82
100
|
end
|
83
101
|
end
|
84
|
-
|
85
|
-
|
86
|
-
spinner = TTY::Spinner.new("Provisioning #{args[:platform]} using #{args[:provisioner]} provisioner.[:spinner]")
|
87
|
-
spinner.auto_spin
|
88
|
-
end
|
89
|
-
results = provision(args[:provisioner], args[:platform], args[:inventory_vars])
|
90
|
-
if results.first['status'] != 'success'
|
91
|
-
raise "Failed provisioning #{args[:platform]} using #{args[:provisioner]}\n#{results.first}"
|
102
|
+
ensure
|
103
|
+
stop_spinner(spinner)
|
92
104
|
end
|
93
105
|
|
94
|
-
if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
|
95
|
-
Thread.kill(progress)
|
96
|
-
else
|
97
|
-
spinner.success
|
98
|
-
end
|
99
106
|
puts "#{results.first['value']['node_name']}, #{args[:platform]}"
|
100
107
|
end
|
101
108
|
|
@@ -118,36 +125,37 @@ namespace :litmus do
|
|
118
125
|
|
119
126
|
results = install_agent(args[:collection], targets, inventory_hash)
|
120
127
|
results.each do |result|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
128
|
+
command_to_run = "bolt task run puppet_agent::install --targets #{result['target']} --inventoryfile inventory.yaml --modulepath #{DEFAULT_CONFIG_DATA['modulepath']}"
|
129
|
+
raise "Failed on #{result['target']}\n#{result}\ntry running '#{command_to_run}'" if result['status'] != 'success'
|
130
|
+
|
131
|
+
# validate successful install
|
132
|
+
puts "Successfull install result: #{result.inspect}" if ENV['DEBUG'] == 'true'
|
133
|
+
retries = 0
|
134
|
+
begin
|
135
|
+
responses = run_command('puppet --version', targets, options: {}, config: DEFAULT_CONFIG_DATA, inventory: inventory_hash.clone)
|
136
|
+
responses.each do |response|
|
137
|
+
raise "Error checking puppet version on #{response.to_json}" if response['status'] != 'success'
|
138
|
+
end
|
139
|
+
rescue StandardError => e
|
140
|
+
puts "ERROR:#{e}" if ENV['DEBUG'] == 'true'
|
141
|
+
# fix the path
|
142
|
+
path_changes = configure_path(inventory_hash)
|
143
|
+
if ENV['DEBUG'] == 'true'
|
137
144
|
path_changes.each do |change|
|
138
145
|
puts "Configuring puppet path result: #{change.inspect}"
|
139
146
|
end
|
140
|
-
|
141
|
-
retries += 1
|
142
|
-
sleep 3
|
143
|
-
retry if retries <= 300
|
144
|
-
raise 'Failed to detect installed puppet version after 5 minutes'
|
145
147
|
end
|
146
148
|
|
147
|
-
|
148
|
-
|
149
|
+
retries += 1
|
150
|
+
sleep 3
|
151
|
+
retry if retries <= 300
|
152
|
+
raise 'Failed to detect installed puppet version after 5 minutes'
|
149
153
|
end
|
154
|
+
|
155
|
+
# add puppet-agent feature to successful nodes
|
156
|
+
inventory_hash = add_feature_to_node(inventory_hash, 'puppet-agent', result['target'])
|
150
157
|
end
|
158
|
+
|
151
159
|
# update the inventory with the puppet-agent feature set per node
|
152
160
|
write_to_inventory_file(inventory_hash, 'inventory.yaml')
|
153
161
|
end
|
@@ -362,7 +370,7 @@ namespace :litmus do
|
|
362
370
|
success_list = []
|
363
371
|
failure_list = []
|
364
372
|
# Provision targets depending on what environment we're in
|
365
|
-
if
|
373
|
+
if ENV['CI'] == 'true'
|
366
374
|
# CI systems are strange beasts, we only output a '.' every wee while to keep the terminal alive.
|
367
375
|
puts "Running against #{targets.size} targets.\n"
|
368
376
|
progress = Thread.new do
|
@@ -379,7 +387,7 @@ namespace :litmus do
|
|
379
387
|
at_exit { exit! }
|
380
388
|
|
381
389
|
env = options[:env].nil? ? {} : options[:env]
|
382
|
-
env['
|
390
|
+
env['HONEYCOMB_TRACE'] = Honeycomb.current_span.to_trace_header
|
383
391
|
stdout, stderr, status = Open3.capture3(env, test)
|
384
392
|
["\n================\n#{title}\n", stdout, stderr, status]
|
385
393
|
end
|
@@ -397,7 +405,7 @@ namespace :litmus do
|
|
397
405
|
spinners = TTY::Spinner::Multi.new("[:spinner] Running against #{targets.size} targets.")
|
398
406
|
payloads.each do |title, test, options|
|
399
407
|
env = options[:env].nil? ? {} : options[:env]
|
400
|
-
env['
|
408
|
+
env['HONEYCOMB_TRACE'] = Honeycomb.current_span.to_trace_header
|
401
409
|
spinners.register("[:spinner] #{title}") do |sp|
|
402
410
|
stdout, stderr, status = Open3.capture3(env, test)
|
403
411
|
if status.to_i.zero?
|
File without changes
|
@@ -77,6 +77,42 @@ RSpec.describe PuppetLitmus::RakeHelper do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
+
context 'with bulk tear_down' do
|
81
|
+
let(:inventory_hash) do
|
82
|
+
{ 'groups' =>
|
83
|
+
[{ 'name' => 'ssh_nodes', 'targets' =>
|
84
|
+
[
|
85
|
+
{ 'uri' => 'one.host', 'facts' => { 'provisioner' => 'abs', 'platform' => 'ubuntu-1604-x86_64', 'job_id' => 'iac-task-pid-21648' } },
|
86
|
+
{ 'uri' => 'two.host', 'facts' => { 'provisioner' => 'abs', 'platform' => 'ubuntu-1804-x86_64', 'job_id' => 'iac-task-pid-21648' } },
|
87
|
+
{ 'uri' => 'three.host', 'facts' => { 'provisioner' => 'abs', 'platform' => 'ubuntu-2004-x86_64', 'job_id' => 'iac-task-pid-21648' } },
|
88
|
+
{ 'uri' => 'four.host', 'facts' => { 'provisioner' => 'abs', 'platform' => 'ubuntu-2004-x86_64', 'job_id' => 'iac-task-pid-21649' } },
|
89
|
+
] }] }
|
90
|
+
end
|
91
|
+
let(:targets) { ['one.host'] }
|
92
|
+
let(:params) { { 'action' => 'tear_down', 'node_name' => 'one.host', 'inventory' => Dir.pwd } }
|
93
|
+
|
94
|
+
it 'calls function' do
|
95
|
+
allow(File).to receive(:directory?).with(File.join(described_class::DEFAULT_CONFIG_DATA['modulepath'], 'provision')).and_return(true)
|
96
|
+
allow_any_instance_of(BoltSpec::Run).to receive(:run_task).with('provision::abs', 'localhost', params, config: described_class::DEFAULT_CONFIG_DATA, inventory: nil).and_return(
|
97
|
+
[{ 'target' => 'localhost',
|
98
|
+
'action' => 'task',
|
99
|
+
'object' => 'provision::abs',
|
100
|
+
'status' => 'success',
|
101
|
+
'value' =>
|
102
|
+
{ 'status' => 'ok',
|
103
|
+
'removed' =>
|
104
|
+
['one.host',
|
105
|
+
'two.host',
|
106
|
+
'three.host'] } }],
|
107
|
+
)
|
108
|
+
results = tear_down_nodes(targets, inventory_hash)
|
109
|
+
expect(results.keys).to eq(['one.host', 'two.host', 'three.host'])
|
110
|
+
results.each_value do |value|
|
111
|
+
expect(value[0]['value']).to eq({ 'status' => 'ok' })
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
80
116
|
context 'with install_agent' do
|
81
117
|
let(:inventory_hash) do
|
82
118
|
{ 'groups' =>
|
@@ -68,7 +68,13 @@ describe 'litmus rake tasks' do
|
|
68
68
|
|
69
69
|
allow(File).to receive(:directory?).with(any_args).and_return(true)
|
70
70
|
allow_any_instance_of(BoltSpec::Run).to receive(:run_task).with(any_args).and_return(results)
|
71
|
+
allow_any_instance_of(PuppetLitmus::InventoryManipulation).to receive(:inventory_hash_from_inventory_file).with(any_args).and_return({})
|
72
|
+
allow_any_instance_of(PuppetLitmus::RakeHelper).to receive(:check_connectivity?).with(any_args).and_return(true)
|
73
|
+
|
74
|
+
expect($stdout).to receive(:puts).with('Provisioning centos:7 using docker provisioner.')
|
75
|
+
expect($stdout).to receive(:puts).with("Successfully provisioned centos:7 using docker\n")
|
71
76
|
expect($stdout).to receive(:puts).with('localhost:2222, centos:7')
|
77
|
+
|
72
78
|
Rake::Task['litmus:provision'].invoke('docker', 'centos:7')
|
73
79
|
end
|
74
80
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet_litmus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.23.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bolt
|
@@ -90,6 +90,20 @@ dependencies:
|
|
90
90
|
- - "<"
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: 3.0.0
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: retryable
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '3.0'
|
100
|
+
type: :runtime
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - "~>"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '3.0'
|
93
107
|
- !ruby/object:Gem::Dependency
|
94
108
|
name: parallel
|
95
109
|
requirement: !ruby/object:Gem::Requirement
|
@@ -171,10 +185,10 @@ files:
|
|
171
185
|
- spec/data/jim.yaml
|
172
186
|
- spec/lib/puppet_litmus/inventory_manipulation_spec.rb
|
173
187
|
- spec/lib/puppet_litmus/puppet_helpers_spec.rb
|
188
|
+
- spec/lib/puppet_litmus/puppet_litmus_version_spec.rb
|
174
189
|
- spec/lib/puppet_litmus/rake_helper_spec.rb
|
175
190
|
- spec/lib/puppet_litmus/rake_tasks_spec.rb
|
176
191
|
- spec/lib/puppet_litmus/util_spec.rb
|
177
|
-
- spec/lib/puppet_litmus/version_spec.rb
|
178
192
|
- spec/spec_helper.rb
|
179
193
|
homepage: https://github.com/puppetlabs/puppet_litmus
|
180
194
|
licenses:
|
@@ -188,14 +202,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
188
202
|
requirements:
|
189
203
|
- - ">="
|
190
204
|
- !ruby/object:Gem::Version
|
191
|
-
version:
|
205
|
+
version: 2.5.0
|
192
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
207
|
requirements:
|
194
208
|
- - ">="
|
195
209
|
- !ruby/object:Gem::Version
|
196
210
|
version: '0'
|
197
211
|
requirements: []
|
198
|
-
rubygems_version: 3.1.
|
212
|
+
rubygems_version: 3.1.2
|
199
213
|
signing_key:
|
200
214
|
specification_version: 4
|
201
215
|
summary: Providing a simple command line tool for puppet content creators, to enable
|
@@ -203,7 +217,7 @@ summary: Providing a simple command line tool for puppet content creators, to en
|
|
203
217
|
test_files:
|
204
218
|
- spec/spec_helper.rb
|
205
219
|
- spec/lib/puppet_litmus/rake_tasks_spec.rb
|
206
|
-
- spec/lib/puppet_litmus/
|
220
|
+
- spec/lib/puppet_litmus/puppet_litmus_version_spec.rb
|
207
221
|
- spec/lib/puppet_litmus/util_spec.rb
|
208
222
|
- spec/lib/puppet_litmus/inventory_manipulation_spec.rb
|
209
223
|
- spec/lib/puppet_litmus/rake_helper_spec.rb
|