puppet_litmus 0.27.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d77bde09896757aa35ff61163febb315e2d50682b1b2dcdfdbc53b77da576c8
4
- data.tar.gz: d80089f753244e77bf491e4bc9ac14a42e6ae112a85d4b6f41206c38b22b7a07
3
+ metadata.gz: 80914970290db5501971ee324794c82101f204d1c78a74cbd618547f8fb345c0
4
+ data.tar.gz: 596c114a8c75fb36f6ab8350850eca9005036fbdf12ed7d3465e2375c937579e
5
5
  SHA512:
6
- metadata.gz: 31a2ac1b11fb651d06de17648e345fbab6105ceb92ff9da52632bba725f1689a111219040e5dacf25cc775382ea15c3845167318a45a953cfb33ab1ebf509d30
7
- data.tar.gz: 108b085470b7d07a438c105871300f9a5a759443592073239c4c4d9c8648207c51774c9689a951ef3adc4b70796cada4f47b4f3263c295fde5aafa99f41ac472
6
+ metadata.gz: eef1f207558172836438bc1bb5686610af52560bd7eb99ae2ff9ae332fa3705f249587dd4eb4f12c4ffd83c0011d03764dd6fa974b21be4012144829d984a429
7
+ data.tar.gz: 57d962b1ea4e49fd483319514197f5b1d119ab9b69e981c2e3a17f151b71358477b6a7276bbee3101f3d0a5f1d00a0cb081de953dfbf750e1ba6d53016836f58
data/README.md CHANGED
@@ -12,17 +12,39 @@
12
12
  Litmus is a command line tool that allows you to run acceptance tests against Puppet modules.
13
13
 
14
14
  Litmus allows you to:
15
- * Provision targets to test against
16
- * Install a Puppet agent
17
- * Install a module
18
- * Run tests
19
- * Tear down the infrastructure
15
+
16
+ - Provision targets to test against
17
+
18
+ - Install a Puppet agent
19
+
20
+ - Install a module
21
+
22
+ - Run tests
23
+
24
+ - Tear down the infrastructure
20
25
 
21
26
  Litmus also facilitates parallel test runs and running tests in isolation. Each step is standalone, allowing other operations between test runs, such as debugging or configuration updates on the test targets.
22
27
 
23
- Install Litmus as a gem by running ```gem install puppet_litmus```.
28
+ Install Litmus as a gem by running `gem install puppet_litmus`.
29
+
30
+ - Note if you choose to override the `litmus_inventory.yaml` location, please ensure that the directory strutcture you define exists.
31
+
32
+ ## matrix_from_metadata_v2
33
+
34
+ matrix_from_metadata_v2 tool generates github actions matrix from metadata.json
35
+
36
+ How to use it: in the project module root directory run `bundle exec matrix_from_metadata_v2`
37
+
38
+ ### --exclude-platforms parameter
39
+
40
+ matrix_from_metadata_v2 accepts `--exclude-platforms <JSON array>` option in order to exclude some platforms from GA matrixes.
41
+
42
+ In order to use this new functionality just simply run:
43
+
44
+ `$: bundle exec matrix_from_metadata_v2 --exclude-platforms '["debian-11","centos-8"]'`
24
45
 
25
- * Note if you choose to override the `litmus_inventory.yaml` location, please ensure that the directory strutcture you define exists.
46
+ > Note: The option value should be JSON string otherwise it will throw an error.
47
+ > The values provided in the json array are case-insensitive `["debian-11","centos-8"]'` or `["Debian-11","CentOS-8"]'` are treated as being the same.
26
48
 
27
49
  ## Documentation
28
50
 
@@ -30,4 +52,4 @@ For documentation, see our [Litmus Docs Site](https://puppetlabs.github.io/litmu
30
52
 
31
53
  ## Other Resources
32
54
 
33
- * [Is it Worth the Time?](https://xkcd.com/1205/)
55
+ - [Is it Worth the Time?](https://xkcd.com/1205/)
@@ -13,15 +13,19 @@ IMAGE_TABLE = {
13
13
  'Windows-2012 R2' => 'windows-2012-r2-core',
14
14
  'Windows-2016' => 'windows-2016',
15
15
  'Windows-2019' => 'windows-2019-core',
16
+ 'Windows-2022' => 'windows-2022',
16
17
  }.freeze
17
18
 
18
19
  DOCKER_PLATFORMS = {
19
20
  'CentOS-6' => 'litmusimage/centos:6',
20
21
  'CentOS-7' => 'litmusimage/centos:7',
21
22
  'CentOS-8' => 'litmusimage/centos:8',
22
- 'Debian-10' => 'litmusimage/debian:10',
23
+ 'Rocky-8' => 'litmusimage/rockylinux:8',
24
+ 'AlmaLinux-8' => 'litmusimage/almalinux:8',
23
25
  # 'Debian-8' => 'litmusimage/debian:8', Removing from testing: https://puppet.com/docs/pe/2021.0/supported_operating_systems.html
24
26
  'Debian-9' => 'litmusimage/debian:9',
27
+ 'Debian-10' => 'litmusimage/debian:10',
28
+ 'Debian-11' => 'litmusimage/debian:11',
25
29
  'OracleLinux-6' => 'litmusimage/oraclelinux:6',
26
30
  'OracleLinux-7' => 'litmusimage/oraclelinux:7',
27
31
  'Scientific-6' => 'litmusimage/scientificlinux:6',
@@ -54,26 +58,45 @@ spec_matrix = {
54
58
  include: [],
55
59
  }
56
60
 
57
- metadata = JSON.parse(File.read('metadata.json'))
61
+ if ARGV.include?('--exclude-platforms')
62
+ exclude_platforms_occurencies = ARGV.select { |arg| arg == '--exclude-platforms' }.length
63
+ raise '--exclude-platforms argument should be present just one time in the command' unless exclude_platforms_occurencies <= 1
64
+
65
+ exclude_platforms_list = ARGV[ARGV.find_index('--exclude-platforms') + 1]
66
+ raise 'you need to provide a list of platforms in JSON format' if exclude_platforms_list.nil?
67
+
68
+ begin
69
+ exclude_list = JSON.parse(exclude_platforms_list).map { |platform| platform.downcase }
70
+ rescue JSON::ParserError
71
+ raise 'the exclude platforms list must valid JSON'
72
+ end
73
+ else
74
+ exclude_list = []
75
+ end
76
+
77
+ metadata_path = ENV['TEST_MATRIX_FROM_METADATA'] || 'metadata.json'
78
+ metadata = JSON.parse(File.read(metadata_path))
58
79
  # Set platforms based on declared operating system support
59
80
  metadata['operatingsystem_support'].sort_by { |a| a['operatingsystem'] }.each do |sup|
60
81
  os = sup['operatingsystem']
61
82
  sup['operatingsystemrelease'].sort_by { |a| a.to_i }.each do |ver|
62
83
  image_key = "#{os}-#{ver}"
63
- if IMAGE_TABLE.key? image_key
84
+
85
+ if IMAGE_TABLE.key?(image_key) && !exclude_list.include?(image_key.downcase)
64
86
  matrix[:platforms] << {
65
87
  label: image_key,
66
88
  provider: 'provision::provision_service',
67
89
  image: IMAGE_TABLE[image_key],
68
90
  }
69
- elsif DOCKER_PLATFORMS.key? image_key
91
+ elsif DOCKER_PLATFORMS.key?(image_key) && !exclude_list.include?(image_key.downcase)
70
92
  matrix[:platforms] << {
71
93
  label: image_key,
72
94
  provider: 'provision::docker',
73
95
  image: DOCKER_PLATFORMS[image_key],
74
96
  }
75
97
  else
76
- puts "::warning::Cannot find image for #{image_key}"
98
+ puts "::warning::#{image_key} was excluded from testing" if exclude_list.include?(image_key.downcase)
99
+ puts "::warning::Cannot find image for #{image_key}" unless exclude_list.include?(image_key.downcase)
77
100
  end
78
101
  end
79
102
  end
@@ -6,8 +6,8 @@ module PuppetLitmus; end # rubocop:disable Style/Documentation
6
6
  module PuppetLitmus::InventoryManipulation
7
7
  # Creates an inventory hash from the inventory.yaml.
8
8
  #
9
- # @param inventory_full_path [String] path to the inventory.yaml file
10
- # @return [Hash] hash of the inventory.yaml file.
9
+ # @param inventory_full_path [String] path to the litmus_inventory.yaml file
10
+ # @return [Hash] hash of the litmus_inventory.yaml file.
11
11
  def inventory_hash_from_inventory_file(inventory_full_path = nil)
12
12
  require 'yaml'
13
13
  inventory_full_path = if inventory_full_path.nil?
@@ -53,6 +53,85 @@ module PuppetLitmus::InventoryManipulation
53
53
  end
54
54
  end
55
55
 
56
+ # Recursively find and iterate over the groups in an inventory. If no block is passed
57
+ # to the function then only the name of the group is returned. If a block is passed
58
+ # then the block is executed against each group and the value of the block is returned.
59
+ #
60
+ # @param inventory_hash [Hash] Inventory hash from inventory.yaml
61
+ # @param block [Block] Block to execute against each node
62
+ def groups_in_inventory(inventory_hash, &block)
63
+ inventory_hash['groups'].flat_map do |group|
64
+ output_collector = []
65
+ output_collector << if block_given?
66
+ yield group
67
+ else
68
+ group['name'].downcase
69
+ end
70
+ output_collector << groups_in_inventory({ 'groups' => group['groups'] }, &block) if group.key? 'groups'
71
+ output_collector.flatten.compact
72
+ end
73
+ end
74
+
75
+ # Iterate over all targets in an inventory. If no block is given to the function
76
+ # it will return the name of every target in the inventory. If a block is passed
77
+ # it will execute the block on each target and return the value of the block.
78
+ #
79
+ # @param inventory_hash [Hash] Inventory hash from inventory.yaml
80
+ # @param block [Block] Block to execute against each node
81
+ def targets_in_inventory(inventory_hash)
82
+ groups_in_inventory(inventory_hash) do |group|
83
+ if group.key? 'targets'
84
+ group['targets'].map do |target|
85
+ if block_given?
86
+ (yield target)
87
+ else
88
+ target['uri'].downcase
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # Find all targets in an inventory that have a role. The roles for a target are
96
+ # specified in the vars hash for a target. This function is tolerant to the roles
97
+ # hash being called either 'role' or 'roles' and it is tolerant to the roles being
98
+ # either a single key value or an array of roles.
99
+ #
100
+ # @param role [String] The name of a role to search for
101
+ # @param inventory [Hash] Inventory hash from inventory.yaml
102
+ def nodes_with_role(role, inventory)
103
+ output_collector = []
104
+ targets_in_inventory(inventory) do |target|
105
+ vars = target['vars']
106
+ roles = [(vars['role'] || vars['roles'])].flatten
107
+ roles = roles.map { |r| r.downcase }
108
+ output_collector << target['uri'] if roles.include? role.downcase
109
+ end
110
+ output_collector unless output_collector.empty?
111
+ end
112
+
113
+ # Searches through the inventory hash to either validate that a group being targeted exists,
114
+ # validate that a specific target being targeted exists, or resolves role names to a
115
+ # list of nodes to target. Targets and roles can be specified as strings or as symbols, and
116
+ # the functions are tolerant to incorrect capitalization.
117
+ #
118
+ # @param target [String] || [Array[String]] A list of targets
119
+ # @param inventory [Hash] inventory hash from inventory.yaml
120
+ def search_for_target(target, inventory)
121
+ result_collector = []
122
+ groups = groups_in_inventory(inventory)
123
+ Array(target).map do |name|
124
+ result_collector << name if groups.include? name.to_s.downcase
125
+ result_collector << name if targets_in_inventory(inventory).include? name.to_s.downcase
126
+ result_collector << nodes_with_role(name.to_s, inventory)
127
+ end
128
+
129
+ result_collector = result_collector.flatten.compact
130
+ raise 'targets not found in inventory' if result_collector.empty?
131
+
132
+ result_collector
133
+ end
134
+
56
135
  # Determines if a node_name exists in a group in the inventory_hash.
57
136
  #
58
137
  # @param inventory_hash [Hash] hash of the inventory.yaml file
@@ -86,14 +165,13 @@ module PuppetLitmus::InventoryManipulation
86
165
  # @param node_name [String] node to locate in the group
87
166
  # @return [Hash] config for node of name node_name
88
167
  def config_from_node(inventory_hash, node_name)
89
- inventory_hash['groups'].each do |group|
90
- group['targets'].each do |node|
91
- if node['uri'] == node_name
92
- return node['config']
93
- end
94
- end
168
+ config = targets_in_inventory(inventory_hash) do |target|
169
+ next unless target['uri'].downcase == node_name.downcase
170
+
171
+ return target['config'] unless target['config'].nil?
95
172
  end
96
- raise "No config was found for #{node_name}"
173
+
174
+ config.empty? ? nil : config[0]
97
175
  end
98
176
 
99
177
  # Finds a facts hash in the inventory hash by searching for a node name.
@@ -102,14 +180,13 @@ module PuppetLitmus::InventoryManipulation
102
180
  # @param node_name [String] node to locate in the group
103
181
  # @return [Hash] facts for node of name node_name
104
182
  def facts_from_node(inventory_hash, node_name)
105
- inventory_hash['groups'].each do |group|
106
- group['targets'].each do |node|
107
- if node['uri'] == node_name
108
- return node['facts']
109
- end
110
- end
183
+ facts = targets_in_inventory(inventory_hash) do |target|
184
+ next unless target['uri'].downcase == node_name.downcase
185
+
186
+ target['facts'] unless target['facts'].nil?
111
187
  end
112
- raise "No facts were found for #{node_name}"
188
+
189
+ facts.empty? ? nil : facts[0]
113
190
  end
114
191
 
115
192
  # Finds a var hash in the inventory hash by searching for a node name.
@@ -118,14 +195,12 @@ module PuppetLitmus::InventoryManipulation
118
195
  # @param node_name [String] node to locate in the group
119
196
  # @return [Hash] vars for node of name node_name
120
197
  def vars_from_node(inventory_hash, node_name)
121
- inventory_hash['groups'].each do |group|
122
- group['targets'].each do |node|
123
- if node['uri'] == node_name
124
- return node['vars']
125
- end
126
- end
198
+ vars = targets_in_inventory(inventory_hash) do |target|
199
+ next unless target['uri'].downcase == node_name.downcase
200
+
201
+ target['vars'] unless target['vars'].nil?
127
202
  end
128
- {}
203
+ vars.empty? ? {} : vars[0]
129
204
  end
130
205
 
131
206
  # Adds a node to a group specified, if group_name exists in inventory hash.
@@ -266,4 +341,27 @@ module PuppetLitmus::InventoryManipulation
266
341
  end
267
342
  Honeycomb.current_span.add_field('litmus.platform', facts&.dig('platform'))
268
343
  end
344
+
345
+ # Add platform custom information field to the current span for each node being targeted.
346
+ # If more than one node is being targeted, each node will be given a separate custom field.
347
+ #
348
+ # @param span [Honeycomb::Span] The current span
349
+ # @param target_node_names [Array[String]] Nodes being targeted
350
+ # @param inventory_hash [Hash] Hash of the inventory.yaml file
351
+ def add_node_fields_to_span(span, target_node_names, inventory_hash)
352
+ node_counter = 1
353
+ Array(target_node_names).each do |target_name|
354
+ name_field = 'litmus.node_name'
355
+ platform_field = 'litmus.platform'
356
+
357
+ name_field = "#{name_field}_#{node_counter}"
358
+ platform_field = "#{platform_field}_#{node_counter}"
359
+ span.add_field(name_field, target_name)
360
+ if target_in_inventory?(inventory_hash, target_name)
361
+ facts = facts_from_node(inventory_hash, target_name)
362
+ span.add_field(platform_field, facts&.dig('platform')) unless facts.nil?
363
+ end
364
+ node_counter += 1
365
+ end
366
+ end
269
367
  end
@@ -6,13 +6,24 @@ module PuppetLitmus::PuppetHelpers
6
6
  # Applies a manifest twice. First checking for errors. Secondly to make sure no changes occur.
7
7
  #
8
8
  # @param manifest [String] puppet manifest code to be applied.
9
+ # @param opts [Hash] Alters the behaviour of the command. Valid options are:
10
+ # :catch_changes [Boolean] (false) We're after idempotency so allow exit code 0 only.
11
+ # :expect_changes [Boolean] (false) We're after changes specifically so allow exit code 2 only.
12
+ # :catch_failures [Boolean] (false) We're after only complete success so allow exit codes 0 and 2 only.
13
+ # :expect_failures [Boolean] (false) We're after failures specifically so allow exit codes 1, 4, and 6 only.
14
+ # :manifest_file_location [Path] The place on the target system.
15
+ # :hiera_config [Path] The path to the hiera.yaml configuration on the target.
16
+ # :prefix_command [String] prefixes the puppet apply command; eg "export LANGUAGE='ja'".
17
+ # :trace [Boolean] run puppet apply with the trace flag (defaults to `true`).
18
+ # :debug [Boolean] run puppet apply with the debug flag.
19
+ # :noop [Boolean] run puppet apply with the noop flag.
9
20
  # @return [Boolean] The result of the 2 apply manifests.
10
- def idempotent_apply(manifest)
21
+ def idempotent_apply(manifest, opts = {})
11
22
  Honeycomb.start_span(name: 'litmus.idempotent_apply') do |span|
12
23
  ENV['HONEYCOMB_TRACE'] = span.to_trace_header
13
24
  manifest_file_location = create_manifest_file(manifest)
14
- apply_manifest(nil, catch_failures: true, manifest_file_location: manifest_file_location)
15
- apply_manifest(nil, catch_changes: true, manifest_file_location: manifest_file_location)
25
+ apply_manifest(nil, **opts, catch_failures: true, manifest_file_location: manifest_file_location)
26
+ apply_manifest(nil, **opts, catch_changes: true, manifest_file_location: manifest_file_location)
16
27
  end
17
28
  end
18
29
 
@@ -70,10 +81,15 @@ module PuppetLitmus::PuppetHelpers
70
81
 
71
82
  manifest_file_location = opts[:manifest_file_location] || create_manifest_file(manifest)
72
83
  inventory_hash = File.exist?('spec/fixtures/litmus_inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
73
- raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
74
84
 
75
- span.add_field('litmus.node_name', target_node_name)
76
- add_platform_field(inventory_hash, target_node_name)
85
+ target_option = opts['targets'] || opts[:targets]
86
+ if target_option.nil?
87
+ raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
88
+ else
89
+ target_node_name = search_for_target(target_option, inventory_hash)
90
+ end
91
+
92
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
77
93
 
78
94
  # Forcibly set the locale of the command
79
95
  locale = if os[:family] != 'windows'
@@ -132,7 +148,7 @@ module PuppetLitmus::PuppetHelpers
132
148
  #
133
149
  # @param manifest [String] puppet manifest code.
134
150
  # @return [String] The path to the location of the manifest.
135
- def create_manifest_file(manifest)
151
+ def create_manifest_file(manifest, opts = {})
136
152
  Honeycomb.start_span(name: 'litmus.create_manifest_file') do |span|
137
153
  ENV['HONEYCOMB_TRACE'] = span.to_trace_header
138
154
  span.add_field('litmus.manifest', manifest)
@@ -149,8 +165,9 @@ module PuppetLitmus::PuppetHelpers
149
165
  else
150
166
  # transfer to TARGET_HOST
151
167
  inventory_hash = inventory_hash_from_inventory_file
152
- span.add_field('litmus.node_name', target_node_name)
153
- add_platform_field(inventory_hash, target_node_name)
168
+ target_option = opts['targets'] || opts[:targets]
169
+ target_node_name = search_for_target(target_option, inventory_hash) unless target_option.nil?
170
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
154
171
 
155
172
  manifest_file_location = File.basename(manifest_file)
156
173
  bolt_result = upload_file(manifest_file.path, manifest_file_location, target_node_name, options: {}, config: nil, inventory: inventory_hash)
@@ -169,13 +186,16 @@ module PuppetLitmus::PuppetHelpers
169
186
  # @param content [String] String data to write to the file.
170
187
  # @param destination [String] The path on the target node to write the file.
171
188
  # @return [Bool] Success. The file was succesfully writtne on the target.
172
- def write_file(content, destination)
189
+ def write_file(content, destination, opts = {})
173
190
  Honeycomb.start_span(name: 'litmus.write_file') do |span|
174
191
  ENV['HONEYCOMB_TRACE'] = span.to_trace_header
175
192
  span.add_field('litmus.destination', destination)
176
193
 
177
194
  require 'tmpdir'
195
+ inventory_hash = inventory_hash_from_inventory_file
178
196
  target_node_name = ENV['TARGET_HOST']
197
+ target_option = opts['targets'] || opts[:targets]
198
+ target_node_name = search_for_target(target_option, inventory_hash) unless target_option.nil?
179
199
 
180
200
  Tempfile.create('litmus') do |tmp_file|
181
201
  tmp_file.write(content)
@@ -186,9 +206,7 @@ module PuppetLitmus::PuppetHelpers
186
206
  FileUtils.cp(tmp_file.path, destination)
187
207
  else
188
208
  # transfer to TARGET_HOST
189
- inventory_hash = inventory_hash_from_inventory_file
190
- span.add_field('litmus.node_name', target_node_name)
191
- add_platform_field(inventory_hash, target_node_name)
209
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
192
210
 
193
211
  bolt_result = upload_file(tmp_file.path, destination, target_node_name, options: {}, config: nil, inventory: inventory_hash)
194
212
  span.add_field('litmus.bolt_result.file_upload', bolt_result)
@@ -212,12 +230,17 @@ module PuppetLitmus::PuppetHelpers
212
230
  span.add_field('litmus.command_to_run', command_to_run)
213
231
  span.add_field('litmus.opts', opts)
214
232
 
215
- target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
216
233
  inventory_hash = File.exist?('spec/fixtures/litmus_inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
217
- raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
218
234
 
219
- span.add_field('litmus.node_name', target_node_name)
220
- add_platform_field(inventory_hash, target_node_name)
235
+ target_option = opts['targets'] || opts[:targets]
236
+ if target_option.nil?
237
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
238
+ raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
239
+ else
240
+ target_node_name = search_for_target(target_option, inventory_hash)
241
+ end
242
+
243
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
221
244
 
222
245
  bolt_result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
223
246
  span.add_field('litmus.bolt_result', bolt_result)
@@ -251,12 +274,16 @@ module PuppetLitmus::PuppetHelpers
251
274
  span.add_field('litmus.opts', opts)
252
275
  span.add_field('litmus.options', options)
253
276
 
254
- target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
255
277
  inventory_hash = File.exist?('spec/fixtures/litmus_inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
256
- raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
278
+ target_option = opts['targets'] || opts[:targets]
279
+ if target_option.nil?
280
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
281
+ raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
282
+ else
283
+ target_node_name = search_for_target(target_option, inventory_hash)
284
+ end
257
285
 
258
- span.add_field('litmus.node_name', target_node_name)
259
- add_platform_field(inventory_hash, target_node_name)
286
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
260
287
 
261
288
  bolt_result = upload_file(source, destination, target_node_name, options: options, config: nil, inventory: inventory_hash)
262
289
  span.add_field('litmus.bolt_result', bolt_result)
@@ -311,10 +338,15 @@ module PuppetLitmus::PuppetHelpers
311
338
  else
312
339
  localhost_inventory_hash
313
340
  end
314
- raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
315
341
 
316
- span.add_field('litmus.node_name', target_node_name)
317
- add_platform_field(inventory_hash, target_node_name)
342
+ target_option = opts['targets'] || opts[:targets]
343
+ if target_option.nil?
344
+ raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
345
+ else
346
+ target_node_name = search_for_target(target_option, inventory_hash)
347
+ end
348
+
349
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
318
350
 
319
351
  bolt_result = run_task(task_name, target_node_name, params, config: config_data, inventory: inventory_hash)
320
352
  result_obj = {
@@ -372,10 +404,14 @@ module PuppetLitmus::PuppetHelpers
372
404
 
373
405
  target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
374
406
  inventory_hash = File.exist?('spec/fixtures/litmus_inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
375
- raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
407
+ target_option = opts['targets'] || opts[:targets]
408
+ if target_option.nil?
409
+ raise "Target '#{target_node_name}' not found in spec/fixtures/litmus_inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
410
+ else
411
+ target_node_name = search_for_target(target_option, inventory_hash)
412
+ end
376
413
 
377
- span.add_field('litmus.node_name', target_node_name)
378
- add_platform_field(inventory_hash, target_node_name)
414
+ add_node_fields_to_span(span, target_node_name, inventory_hash)
379
415
 
380
416
  bolt_result = run_script(script, target_node_name, arguments, options: opts, config: nil, inventory: inventory_hash)
381
417
 
@@ -464,7 +464,7 @@ module PuppetLitmus::RakeHelper
464
464
 
465
465
  class LitmusTimeoutError < StandardError; end
466
466
 
467
- def with_retries(options: { tries: Float::INFINITY }, max_wait_minutes: 8)
467
+ def with_retries(options: { tries: Float::INFINITY }, max_wait_minutes: 15)
468
468
  stop = Time.now + (max_wait_minutes * 60)
469
469
  Retryable.retryable(options.merge(not: [LitmusTimeoutError])) do
470
470
  raise LitmusTimeoutError if Time.now > stop
@@ -2,5 +2,5 @@
2
2
 
3
3
  # version of this gem
4
4
  module PuppetLitmus
5
- VERSION ||= '0.27.0'
5
+ VERSION ||= '0.31.0'
6
6
  end
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "puppetlabs-fake_module",
3
+ "version": "3.1.0",
4
+ "author": "puppetlabs",
5
+ "summary": "fake_module is a test",
6
+ "license": "Apache-2.0",
7
+ "source": "it has no source",
8
+ "project_page": "it has no project page",
9
+ "issues_url": "https://tickets.puppetlabs.com/browse/MODULES",
10
+ "dependencies": [
11
+ {
12
+ "name": "puppetlabs/stdlib",
13
+ "version_requirement": ">= 4.0.0 < 9.0.0"
14
+ }
15
+ ],
16
+ "operatingsystem_support": [
17
+ {
18
+ "operatingsystem": "CentOS",
19
+ "operatingsystemrelease": [
20
+ "6"
21
+ ]
22
+ },
23
+ {
24
+ "operatingsystem": "RedHat",
25
+ "operatingsystemrelease": [
26
+ "8"
27
+ ]
28
+ },
29
+ {
30
+ "operatingsystem": "Ubuntu",
31
+ "operatingsystemrelease": [
32
+ "14.04",
33
+ "18.04"
34
+ ]
35
+ }
36
+ ],
37
+ "requirements": [
38
+ {
39
+ "name": "puppet",
40
+ "version_requirement": ">= 6.0.0 < 8.0.0"
41
+ }
42
+ ],
43
+ "template-url": "https://github.com/puppetlabs/pdk-templates.git#main",
44
+ "template-ref": "heads/main-0-g2381db6",
45
+ "pdk-version": "2.1.1"
46
+ }
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'matrix_from_metadata_v2' do
6
+ context 'without arguments' do
7
+ let(:result) { run_matrix_from_metadata_v2 }
8
+
9
+ it 'run successfully' do
10
+ expect(result.status_code).to eq 0
11
+ end
12
+
13
+ it 'generates the matrix' do
14
+ expect(result.stdout).to include('::warning::Cannot find image for Ubuntu-14.04')
15
+ expect(result.stdout).to include(
16
+ [
17
+ '::set-output name=matrix::{',
18
+ '"platforms":[',
19
+ '{"label":"CentOS-6","provider":"provision::docker","image":"litmusimage/centos:6"},',
20
+ '{"label":"RedHat-8","provider":"provision::provision_service","image":"rhel-8"},',
21
+ '{"label":"Ubuntu-18.04","provider":"provision::docker","image":"litmusimage/ubuntu:18.04"}',
22
+ '],',
23
+ '"collection":[',
24
+ '"puppet6-nightly","puppet7-nightly"',
25
+ ']',
26
+ '}',
27
+ ].join,
28
+ )
29
+ expect(result.stdout).to include(
30
+ '::set-output name=spec_matrix::{"include":[{"puppet_version":"~> 6.0","ruby_version":2.5},{"puppet_version":"~> 7.0","ruby_version":2.7}]}',
31
+ )
32
+ expect(result.stdout).to include("Created matrix with 8 cells:\n - Acceptance Test Cells: 6\n - Spec Test Cells: 2")
33
+ end
34
+ end
35
+
36
+ context 'with --exclude-platforms ["ubuntu-18.04"]' do
37
+ let(:result) { run_matrix_from_metadata_v2({ '--exclude-platforms' => ['ubuntu-18.04'] }) }
38
+
39
+ it 'run successfully' do
40
+ expect(result.status_code).to eq 0
41
+ end
42
+
43
+ it 'generates the matrix without excluded platforms' do
44
+ expect(result.stdout).to include('::warning::Cannot find image for Ubuntu-14.04')
45
+ expect(result.stdout).to include('::warning::Ubuntu-18.04 was excluded from testing')
46
+ expect(result.stdout).to include(
47
+ [
48
+ '::set-output name=matrix::{',
49
+ '"platforms":[',
50
+ '{"label":"CentOS-6","provider":"provision::docker","image":"litmusimage/centos:6"},',
51
+ '{"label":"RedHat-8","provider":"provision::provision_service","image":"rhel-8"}',
52
+ '],',
53
+ '"collection":[',
54
+ '"puppet6-nightly","puppet7-nightly"',
55
+ ']',
56
+ '}',
57
+ ].join,
58
+ )
59
+ expect(result.stdout).to include(
60
+ '::set-output name=spec_matrix::{"include":[{"puppet_version":"~> 6.0","ruby_version":2.5},{"puppet_version":"~> 7.0","ruby_version":2.7}]}',
61
+ )
62
+ expect(result.stdout).to include("Created matrix with 6 cells:\n - Acceptance Test Cells: 4\n - Spec Test Cells: 2")
63
+ end
64
+ end
65
+
66
+ context 'with --exclude-platforms \'["ubuntu-18.04","redhat-8"]\'' do
67
+ let(:result) { run_matrix_from_metadata_v2({ '--exclude-platforms' => ['ubuntu-18.04', 'redhat-8'] }) }
68
+
69
+ it 'run successfully' do
70
+ expect(result.status_code).to eq 0
71
+ end
72
+
73
+ it 'generates the matrix without excluded platforms' do
74
+ expect(result.stdout).to include('::warning::Cannot find image for Ubuntu-14.04')
75
+ expect(result.stdout).to include('::warning::Ubuntu-18.04 was excluded from testing')
76
+ expect(result.stdout).to include('::warning::RedHat-8 was excluded from testing')
77
+ expect(result.stdout).to include(
78
+ [
79
+ '::set-output name=matrix::{',
80
+ '"platforms":[',
81
+ '{"label":"CentOS-6","provider":"provision::docker","image":"litmusimage/centos:6"}',
82
+ '],',
83
+ '"collection":[',
84
+ '"puppet6-nightly","puppet7-nightly"',
85
+ ']',
86
+ '}',
87
+ ].join,
88
+ )
89
+ expect(result.stdout).to include(
90
+ '::set-output name=spec_matrix::{"include":[{"puppet_version":"~> 6.0","ruby_version":2.5},{"puppet_version":"~> 7.0","ruby_version":2.7}]}',
91
+ )
92
+ expect(result.stdout).to include("Created matrix with 4 cells:\n - Acceptance Test Cells: 2\n - Spec Test Cells: 2")
93
+ end
94
+ end
95
+ end