puppet_litmus 0.18.1 → 0.20.0

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