puppet_litmus 0.18.1 → 0.20.0

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.
@@ -17,15 +17,15 @@ namespace :litmus do
17
17
  end
18
18
 
19
19
  # Provisions a list of OSes from provision.yaml file e.g. 'bundle exec rake litmus:provision_list[default]'.
20
- # @See https://github.com/puppetlabs/puppet_litmus/wiki/Overview-of-Litmus#provisioning-via-yaml
20
+ # @See https://puppetlabs.github.io/litmus/Litmus-core-commands.html#provisioning-via-yaml
21
21
  #
22
22
  # @param :key [String] key that maps to a value for a provisioner and an image to be used for each OS provisioned.
23
- desc "provision list of machines from provision.yaml file. 'bundle exec rake 'litmus:provision_list[default]'"
23
+ desc 'provision list of machines from provision.yaml file'
24
24
  task :provision_list, [:key] do |_task, args|
25
25
  raise 'Cannot find provision.yaml file' unless File.file?('./provision.yaml')
26
26
 
27
27
  provision_hash = YAML.load_file('./provision.yaml')
28
- raise "No key #{args[:key]} in ./provision.yaml, see https://github.com/puppetlabs/puppet_litmus/wiki/Overview-of-Litmus#provisioning-via-yaml for examples" if provision_hash[args[:key]].nil?
28
+ raise "No key #{args[:key]} in ./provision.yaml, see https://puppetlabs.github.io/litmus/Litmus-core-commands.html#provisioning-via-yaml for examples" if provision_hash[args[:key]].nil?
29
29
 
30
30
  Rake::Task['spec_prep'].invoke
31
31
 
@@ -36,30 +36,17 @@ namespace :litmus do
36
36
  results = []
37
37
  failed_image_message = ''
38
38
  provision_hash[args[:key]]['images'].each do |image|
39
- if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
40
- progress = Thread.new do
41
- loop do
42
- printf '.'
43
- sleep(10)
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
39
+ begin
40
+ spinner = start_spinner("Provisioning #{image} using #{provisioner} provisioner.")
41
+ result = provision(provisioner, image, inventory_vars)
42
+ ensure
43
+ stop_spinner(spinner)
57
44
  end
58
45
 
59
46
  if result.first['status'] != 'success'
60
47
  failed_image_message += "=====\n#{result.first['target']}\n#{result.first['value']['_output']}\n#{result.inspect}"
61
48
  else
62
- STDOUT.puts "#{result.first['value']['node_name']}, #{image}"
49
+ $stdout.puts "#{result.first['value']['node_name']}, #{image}"
63
50
  end
64
51
  results << result
65
52
  end
@@ -71,31 +58,38 @@ namespace :litmus do
71
58
  #
72
59
  # @param :provisioner [String] provisioner to use in provisioning given platform.
73
60
  # @param :platform [String] OS platform for container or VM to use.
74
- desc "provision container/VM - abs/docker/vagrant/vmpooler eg 'bundle exec rake 'litmus:provision[vmpooler, ubuntu-1604-x86_64]'"
61
+ desc 'provision a test system using the given provisioner and platform name. See the puppetlabs-provision module tasks for more documentation'
75
62
  task :provision, [:provisioner, :platform, :inventory_vars] do |_task, args|
76
63
  Rake::Task['spec_prep'].invoke
77
- if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
78
- progress = Thread.new do
79
- loop do
80
- printf '.'
81
- sleep(10)
64
+
65
+ begin
66
+ spinner = start_spinner("Provisioning #{args[:platform]} using #{args[:provisioner]} provisioner.")
67
+
68
+ results = provision(args[:provisioner], args[:platform], args[:inventory_vars])
69
+
70
+ unless results.first['status'] == 'success'
71
+ raise "Failed provisioning #{args[:platform]} using #{args[:provisioner]}\n#{results.first}"
72
+ end
73
+
74
+ puts "Successfully provisioned #{args[:platform]} using #{args[:provisioner]}\n"
75
+
76
+ target_names = if results.first['value']['node']
77
+ [results.first['value']['node']['uri']]
78
+ else
79
+ results.first['value']['target_names'] || [] # provision_service multi-node provisioning
80
+ end
81
+ target_names.each do |target|
82
+ Honeycomb.start_span(name: 'litmus.provision.check_connectivity') do |span|
83
+ span.add_field('target_name', target)
84
+ with_retries do
85
+ check_connectivity?(inventory_hash_from_inventory_file, target)
86
+ end
82
87
  end
83
88
  end
84
- else
85
- require 'tty-spinner'
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}"
89
+ ensure
90
+ stop_spinner(spinner)
92
91
  end
93
92
 
94
- if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
95
- Thread.kill(progress)
96
- else
97
- spinner.success
98
- end
99
93
  puts "#{results.first['value']['node_name']}, #{args[:platform]}"
100
94
  end
101
95
 
@@ -103,7 +97,7 @@ namespace :litmus do
103
97
  #
104
98
  # @param :collection [String] parameters to pass to the puppet agent install command.
105
99
  # @param :target_node_name [Array] nodes on which to install puppet agent.
106
- desc 'install puppet agent, [:collection, :target_node_name]'
100
+ desc 'install a puppet agent to all or a specified set of targets'
107
101
  task :install_agent, [:collection, :target_node_name] do |_task, args|
108
102
  inventory_hash = inventory_hash_from_inventory_file
109
103
  targets = find_targets(inventory_hash, args[:target_node_name])
@@ -122,28 +116,43 @@ namespace :litmus do
122
116
  command_to_run = "bolt task run puppet_agent::install --targets #{result['target']} --inventoryfile inventory.yaml --modulepath #{DEFAULT_CONFIG_DATA['modulepath']}"
123
117
  raise "Failed on #{result['target']}\n#{result}\ntry running '#{command_to_run}'"
124
118
  else
119
+ # validate successful install
120
+ puts "Successfull install result: #{result.inspect}" if ENV['DEBUG'] == true
121
+ retries = 0
122
+ begin
123
+ responses = run_command('puppet --version', targets, options: {}, config: DEFAULT_CONFIG_DATA, inventory: inventory_hash.clone)
124
+ responses.each do |response|
125
+ raise "Error checking puppet version on #{response.to_json}" if response['status'] != 'success'
126
+ end
127
+ rescue StandardError => e
128
+ puts "ERROR:#{e}"
129
+ # fix the path
130
+ path_changes = configure_path(inventory_hash)
131
+ if ENV['DEBUG'] == true
132
+ path_changes.each do |change|
133
+ puts "Configuring puppet path result: #{change.inspect}"
134
+ end
135
+ end
136
+
137
+ retries += 1
138
+ sleep 3
139
+ retry if retries <= 300
140
+ raise 'Failed to detect installed puppet version after 5 minutes'
141
+ end
142
+
125
143
  # add puppet-agent feature to successful nodes
126
144
  inventory_hash = add_feature_to_node(inventory_hash, 'puppet-agent', result['target'])
127
145
  end
128
146
  end
129
147
  # update the inventory with the puppet-agent feature set per node
130
148
  write_to_inventory_file(inventory_hash, 'inventory.yaml')
131
-
132
- # fix the path on ssh_nodes
133
- results = configure_path(inventory_hash)
134
-
135
- results.each do |result|
136
- if result['status'] != 'success'
137
- puts "Failed on #{result['target']}\n#{result}"
138
- end
139
- end
140
149
  end
141
150
 
142
151
  # Add a given feature to a selection of nodes
143
152
  #
144
153
  # @param :target_node_name [Array] nodes on which to add the feature.
145
154
  # @param :added_feature [String] the feature which you wish to add.
146
- desc 'add_feature, [:added_feature, :target_node_name]'
155
+ desc 'add a feature tag to a node'
147
156
  task :add_feature, [:added_feature, :target_node_name] do |_task, args|
148
157
  inventory_hash = inventory_hash_from_inventory_file
149
158
  targets = find_targets(inventory_hash, args[:target_node_name])
@@ -166,83 +175,118 @@ namespace :litmus do
166
175
  puts 'Feature added'
167
176
  end
168
177
 
178
+ # Install the puppet module under test on a collection of nodes
179
+ #
180
+ # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
181
+ desc 'build the module under test and install it onto targets'
182
+ task :install_module, [:target_node_name, :module_repository] do |_task, args|
183
+ args.with_defaults(target_node_name: nil, module_repository: nil)
184
+ inventory_hash = inventory_hash_from_inventory_file
185
+ target_nodes = find_targets(inventory_hash, args[:target_node_name])
186
+ if target_nodes.empty?
187
+ puts 'No targets found'
188
+ exit 0
189
+ end
190
+
191
+ module_tar = build_module
192
+ puts "Built '#{module_tar}'"
193
+
194
+ # module_tar = Dir.glob('pkg/*.tar.gz').max_by { |f| File.mtime(f) }
195
+ raise "Unable to find package in 'pkg/*.tar.gz'" if module_tar.nil?
196
+
197
+ install_module(inventory_hash, args[:target_node_name], module_tar, args[:module_repository])
198
+
199
+ puts "Installed '#{module_tar}' on #{args[:target_node_name]}"
200
+ end
201
+
169
202
  # Install the puppet modules from a source directory to nodes. It does not install dependencies.
170
203
  #
171
204
  # @param :source [String] source directory to look in (ignores symlinks) defaults do './spec/fixtures/modules'.
172
205
  # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
173
- desc 'install_module - build and install module'
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')
206
+ desc 'build and install all modules from a directory'
207
+ task :install_modules_from_directory, [:source, :target_node_name, :module_repository, :ignore_dependencies] do |_task, args|
208
+ args.with_defaults(source: nil, target_node_name: nil, module_repository: nil, ignore_dependencies: false)
176
209
  inventory_hash = inventory_hash_from_inventory_file
177
210
  target_nodes = find_targets(inventory_hash, args[:target_node_name])
178
211
  if target_nodes.empty?
179
212
  puts 'No targets found'
180
213
  exit 0
181
214
  end
182
- source_folder = if args[:source].nil?
183
- './spec/fixtures/modules'
184
- else
185
- File.expand_path(args[:source])
186
- end
187
- raise "Source folder doesnt exist #{source_folder}" unless File.directory?(source_folder)
188
-
189
- puts 'Building'
190
- module_tars = build_modules_in_folder(source_folder)
215
+ source_dir = if args[:source].nil?
216
+ './spec/fixtures/modules'
217
+ else
218
+ File.expand_path(args[:source])
219
+ end
220
+ raise "Source directory doesn't exist #{source_dir}" unless File.directory?(source_dir)
221
+
222
+ puts "Building all modules in #{source_dir.inspect}"
223
+ module_tars = build_modules_in_dir(source_dir)
191
224
  require 'bolt_spec/run'
192
225
  include BoltSpec::Run
193
- puts "\nInstalling"
194
226
  module_tars.each do |module_tar|
227
+ puts "Installing '#{module_tar}'"
195
228
  target_nodes.each do |target_node_name|
196
- install_module(inventory_hash, target_node_name, module_tar, args[:module_repository])
229
+ install_module(inventory_hash, target_node_name, module_tar, args[:module_repository], args[:ignore_dependencies])
230
+ puts "Installed '#{module_tar}' on #{target_node_name}"
197
231
  end
198
232
  end
199
233
  end
200
234
 
201
- # Check that the nodes in the inventory are still contactable
235
+ # Uninstall the puppet module under test on a collection of nodes
202
236
  #
203
- # @param :target_node_name [Array] nodes on which to check connnectivity
204
- desc 'check_connectivity - build and install module'
205
- task :check_connectivity, [:target_node_name] do |_task, args|
237
+ # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
238
+ # @param :module_name [String] module name to be uninstalled
239
+ desc 'uninstall a specific module'
240
+ task :uninstall_module, [:target_node_name, :module_name] do |_task, args|
206
241
  inventory_hash = inventory_hash_from_inventory_file
207
242
  target_nodes = find_targets(inventory_hash, args[:target_node_name])
208
243
  if target_nodes.empty?
209
244
  puts 'No targets found'
210
245
  exit 0
211
246
  end
212
- check_connectivity?(inventory_hash, args[:target_node_name])
247
+
248
+ result = uninstall_module(inventory_hash, args[:target_node_name], args[:module_name])
249
+
250
+ raise "Failed trying to run 'puppet module uninstall #{module_name}' against inventory." unless result.is_a?(Array)
251
+
252
+ result.each do |node|
253
+ puts "#{node['target']} failed #{node['value']}" if node['status'] != 'success'
254
+ end
255
+
256
+ puts 'Uninstalled'
213
257
  end
214
258
 
215
- # Install the puppet module under test on a collection of nodes
259
+ # Reinstall the puppet module under test on a collection of nodes
216
260
  #
217
261
  # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
218
- desc 'install_module - build and install module'
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')
262
+ desc 'reinstall the module under test'
263
+ task :reinstall_module, [:target_node_name, :module_repository] do |_task, args|
264
+ args.with_defaults(target_node_name: nil, module_repository: nil)
265
+ Rake::Task['litmus:uninstall_module'].invoke(args[:target_node_name])
266
+ Rake::Task['litmus:install_module'].invoke(args[:target_node_name], args[:module_repository])
267
+ end
268
+
269
+ # Check that the nodes in the inventory are still contactable
270
+ #
271
+ # @param :target_node_name [Array] nodes on which to check connnectivity
272
+ desc 'check the connectivity to all provisioned targets'
273
+ task :check_connectivity, [:target_node_name] do |_task, args|
221
274
  inventory_hash = inventory_hash_from_inventory_file
222
275
  target_nodes = find_targets(inventory_hash, args[:target_node_name])
223
276
  if target_nodes.empty?
224
277
  puts 'No targets found'
225
278
  exit 0
226
279
  end
227
-
228
- module_tar = build_module
229
- puts 'Built'
230
-
231
- # module_tar = Dir.glob('pkg/*.tar.gz').max_by { |f| File.mtime(f) }
232
- raise "Unable to find package in 'pkg/*.tar.gz'" if module_tar.nil?
233
-
234
- install_module(inventory_hash, args[:target_node_name], module_tar, args[:module_repository])
235
-
236
- puts 'Installed'
280
+ check_connectivity?(inventory_hash, args[:target_node_name])
237
281
  end
238
282
 
239
283
  # Provision a list of machines, install a puppet agent, and install the puppet module under test on a collection of nodes
240
284
  #
241
285
  # @param :key [String] key that maps to a value for a provisioner and an image to be used for each OS provisioned.
242
286
  # @param :collection [String] parameters to pass to the puppet agent install command.
243
- desc 'provision_install - provision a list of machines, install an agent, and the module.'
287
+ desc 'provision a list of machines, install an agent, and the module.'
244
288
  task :provision_install, [:key, :collection, :module_repository] do |_task, args|
245
- args.with_defaults(module_repository: 'https://forgeapi.puppetlabs.com')
289
+ args.with_defaults(module_repository: nil)
246
290
  Rake::Task['spec_prep'].invoke
247
291
  Rake::Task['litmus:provision_list'].invoke(args[:key])
248
292
  Rake::Task['litmus:install_agent'].invoke(args[:collection])
@@ -252,7 +296,7 @@ namespace :litmus do
252
296
  # Decommissions test machines.
253
297
  #
254
298
  # @param :target [Array] nodes to remove from test environemnt and decommission.
255
- desc 'tear-down - decommission machines'
299
+ desc 'destroy provisioned targets'
256
300
  task :tear_down, [:target] do |_task, args|
257
301
  inventory_hash = inventory_hash_from_inventory_file
258
302
  targets = find_targets(inventory_hash, args[:target])
@@ -278,40 +322,6 @@ namespace :litmus do
278
322
  end
279
323
  end
280
324
 
281
- # Uninstall the puppet module under test on a collection of nodes
282
- #
283
- # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
284
- # @param :module_name [String] module name to be uninstalled
285
- desc 'uninstall_module - uninstall module'
286
- task :uninstall_module, [:target_node_name, :module_name] do |_task, args|
287
- inventory_hash = inventory_hash_from_inventory_file
288
- target_nodes = find_targets(inventory_hash, args[:target_node_name])
289
- if target_nodes.empty?
290
- puts 'No targets found'
291
- exit 0
292
- end
293
-
294
- result = uninstall_module(inventory_hash, args[:target_node_name], args[:module_name])
295
-
296
- raise "Failed trying to run 'puppet module uninstall #{module_name}' against inventory." unless result.is_a?(Array)
297
-
298
- result.each do |node|
299
- puts "#{node['target']} failed #{node['value']}" if node['status'] != 'success'
300
- end
301
-
302
- puts 'Uninstalled'
303
- end
304
-
305
- # Reinstall the puppet module under test on a collection of nodes
306
- #
307
- # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
308
- desc 'reinstall_module - reinstall module'
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')
311
- Rake::Task['litmus:uninstall_module'].invoke(args[:target_node_name])
312
- Rake::Task['litmus:install_module'].invoke(args[:target_node_name], args[:module_repository])
313
- end
314
-
315
325
  namespace :acceptance do
316
326
  require 'rspec/core/rake_task'
317
327
  if File.file?('inventory.yaml')
@@ -320,15 +330,21 @@ namespace :litmus do
320
330
 
321
331
  # Run acceptance tests against all machines in the inventory file in parallel.
322
332
  desc 'Run tests in parallel against all machines in the inventory file'
323
- task :parallel do
333
+ task :parallel, [:tag] do |_task, args|
334
+ args.with_defaults(tag: nil)
324
335
  if targets.empty?
325
336
  puts 'No targets found'
326
337
  exit 0
327
338
  end
339
+ tag_value = if args[:tag].nil?
340
+ nil
341
+ else
342
+ "--tag #{args[:tag]}"
343
+ end
328
344
  payloads = []
329
345
  # Generate list of targets to provision
330
346
  targets.each do |target|
331
- test = 'bundle exec rspec ./spec/acceptance --format progress --require rspec_honeycomb_formatter --format RSpecHoneycombFormatter'
347
+ test = "bundle exec rspec ./spec/acceptance #{tag_value} --format progress --require rspec_honeycomb_formatter --format RSpecHoneycombFormatter"
332
348
  title = "#{target}, #{facts_from_node(inventory_hash, target)['platform']}"
333
349
  options = {
334
350
  env: {
@@ -342,7 +358,7 @@ namespace :litmus do
342
358
  success_list = []
343
359
  failure_list = []
344
360
  # Provision targets depending on what environment we're in
345
- if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
361
+ if ENV['CI'] == 'true'
346
362
  # CI systems are strange beasts, we only output a '.' every wee while to keep the terminal alive.
347
363
  puts "Running against #{targets.size} targets.\n"
348
364
  progress = Thread.new do
@@ -366,9 +382,9 @@ namespace :litmus do
366
382
  # because we cannot modify variables inside of Parallel
367
383
  results.each do |result|
368
384
  if result.last.to_i.zero?
369
- success_list.push(result.first.scan(%r{.*})[2])
385
+ success_list.push(result.first.scan(%r{.*})[3])
370
386
  else
371
- failure_list.push(result.first.scan(%r{.*})[2])
387
+ failure_list.push(result.first.scan(%r{.*})[3])
372
388
  end
373
389
  end
374
390
  Thread.kill(progress)
@@ -410,8 +426,9 @@ namespace :litmus do
410
426
  desc "Run serverspec against #{target}"
411
427
  next if target == 'litmus_localhost'
412
428
 
413
- RSpec::Core::RakeTask.new(target.to_sym) do |t|
429
+ RSpec::Core::RakeTask.new(target.to_sym, :tag) do |t, args|
414
430
  t.pattern = 'spec/acceptance/**{,/*/**}/*_spec.rb'
431
+ t.rspec_opts = "--tag #{args[:tag]}" unless args[:tag].nil?
415
432
  ENV['TARGET_HOST'] = target
416
433
  end
417
434
  end
@@ -420,8 +437,9 @@ namespace :litmus do
420
437
  # add localhost separately
421
438
  desc 'Run serverspec against localhost, USE WITH CAUTION, this action can be potentially dangerous.'
422
439
  host = 'localhost'
423
- RSpec::Core::RakeTask.new(host.to_sym) do |t|
440
+ RSpec::Core::RakeTask.new(host.to_sym, :tag) do |t, args|
424
441
  t.pattern = 'spec/acceptance/**{,/*/**}/*_spec.rb'
442
+ t.rspec_opts = "--tag #{args[:tag]}" unless args[:tag].nil?
425
443
  Rake::Task['spec_prep'].invoke
426
444
  ENV['TARGET_HOST'] = host
427
445
  end
@@ -35,6 +35,7 @@ module PuppetLitmus
35
35
  options[:port] = node_config.dig('ssh', 'port') unless node_config.dig('ssh', 'port').nil?
36
36
  options[:keys] = node_config.dig('ssh', 'private-key') unless node_config.dig('ssh', 'private-key').nil?
37
37
  options[:password] = node_config.dig('ssh', 'password') unless node_config.dig('ssh', 'password').nil?
38
+ run_as = node_config.dig('ssh', 'run-as') unless node_config.dig('ssh', 'run-as').nil?
38
39
  # Support both net-ssh 4 and 5.
39
40
  # rubocop:disable Metrics/BlockNesting
40
41
  options[:verify_host_key] = if node_config.dig('ssh', 'host-key-check').nil?
@@ -66,7 +67,9 @@ module PuppetLitmus
66
67
  end
67
68
  set :host, options[:host_name] || host
68
69
  set :ssh_options, options
69
- set :request_pty, true
70
+ set :request_pty, false
71
+ set :sudo_password, options[:password] if run_as
72
+ puts "Running tests as #{run_as}" if run_as
70
73
  elsif target_in_group(inventory_hash, ENV['TARGET_HOST'], 'winrm_nodes')
71
74
  require 'winrm'
72
75