puppet_litmus 0.12.0 → 0.13.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41776234e4a62f7965314cc8c40d33a91ae86c5718a3af4dc3041713c53b86f0
4
- data.tar.gz: a7060ae471bc8f197fc33af71a65bb5dd11cae2d54d139fb607c4e632c6c9590
3
+ metadata.gz: 8fc34d2ba2485c4d4e6cedecc99642a4f1acf98c0861598af4f63b732b1de088
4
+ data.tar.gz: 12cc1dec19bf0ef86b9941870939d0bf2b9cc6251495543be40a33481e747be7
5
5
  SHA512:
6
- metadata.gz: ff8a621cb6df184f8b30af5083fd1eefc945986ae2620df2cc62a8168bf2bee601ce093bbe41baa2ae922bd7796588a3be33413093ba003e1f8b39f72fee1ac0
7
- data.tar.gz: 4533bda3c00d1e45463ed4c4f52d90e719610f7895ace22d7b8f2d5d24f4c0407a0280d874dbb554d769e97d06f32e506d1a8a9b1faddde6bb85269417a114e9
6
+ metadata.gz: 0c1532fb9b58f22974322d139e0775b4821993b5bb03748d7dbff4b1704ea4b400e80e755225a9a410ae7f96c0d1489c59f58bf988923a612c26e8f190c78718
7
+ data.tar.gz: d88135655e933a2ce8da0b4edf552fca12a85ed552a3d02338e61538d80686b6333eee5ba3411071a41e0459a2437337a9687d471ed99972ab4234203f15c6c0
@@ -6,10 +6,13 @@ module PuppetLitmus; end
6
6
  require 'bolt_spec/run'
7
7
  require 'puppet_litmus/inventory_manipulation'
8
8
  require 'puppet_litmus/puppet_helpers'
9
+ require 'puppet_litmus/rake_helper'
10
+ require 'puppet_litmus/spec_helper_acceptance'
9
11
 
10
12
  # Helper methods for testing puppet content
11
13
  module PuppetLitmus
12
14
  include BoltSpec::Run
13
15
  include PuppetLitmus::InventoryManipulation
14
16
  include PuppetLitmus::PuppetHelpers
17
+ include PuppetLitmus::RakeHelper
15
18
  end
@@ -7,6 +7,7 @@ module PuppetLitmus::InventoryManipulation
7
7
  # @param inventory_full_path [String] path to the inventory.yaml file
8
8
  # @return [Hash] hash of the inventory.yaml file.
9
9
  def inventory_hash_from_inventory_file(inventory_full_path = nil)
10
+ require 'yaml'
10
11
  inventory_full_path = if inventory_full_path.nil?
11
12
  'inventory.yaml'
12
13
  else
@@ -44,6 +45,7 @@ module PuppetLitmus::InventoryManipulation
44
45
  # @param targets [Array]
45
46
  # @return [Array] array of targets.
46
47
  def find_targets(inventory_hash, targets)
48
+ require 'bolt/inventory'
47
49
  if targets.nil?
48
50
  inventory = Bolt::Inventory.new(inventory_hash, nil)
49
51
  targets = inventory.node_names.to_a
@@ -250,6 +252,6 @@ module PuppetLitmus::InventoryManipulation
250
252
  # @param inventory_hash [Hash] hash of the inventory.yaml file
251
253
  # @return inventory.yaml file with feature added to group.
252
254
  def write_to_inventory_file(inventory_hash, inventory_full_path)
253
- File.open(inventory_full_path, 'w+') { |f| f.write(inventory_hash.to_yaml) }
255
+ File.open(inventory_full_path, 'wb+') { |f| f.write(inventory_hash.to_yaml) }
254
256
  end
255
257
  end
@@ -130,6 +130,7 @@ module PuppetLitmus::PuppetHelpers
130
130
  raise "shell failed\n`#{command_to_run}`\n======\n#{result}" if result.first['result']['exit_code'] != 0 && opts[:expect_failures] != true
131
131
 
132
132
  result = OpenStruct.new(exit_code: result.first['result']['exit_code'],
133
+ exit_status: result.first['result']['exit_code'],
133
134
  stdout: result.first['result']['stdout'],
134
135
  stderr: result.first['result']['stderr'])
135
136
  yield result if block_given?
@@ -266,13 +267,13 @@ module PuppetLitmus::PuppetHelpers
266
267
  # @param command [String] The puppet command causing the error.
267
268
  # @param result [Array] The result struct containing the result
268
269
  def report_puppet_apply_error(command, result, acceptable_exit_codes)
269
- puppet_apply_error = <<-ERROR
270
- apply manifest failed
271
- `#{command}`
272
- with exit code #{result.first['result']['exit_code']} (expected: #{acceptable_exit_codes})
273
- ====== Start output of failed Puppet apply ======
274
- #{puppet_output(result)}
275
- ====== End output of failed Puppet apply ======
270
+ puppet_apply_error = <<~ERROR
271
+ apply manifest failed
272
+ `#{command}`
273
+ with exit code #{result.first['result']['exit_code']} (expected: #{acceptable_exit_codes})
274
+ ====== Start output of failed Puppet apply ======
275
+ #{puppet_output(result)}
276
+ ====== End output of failed Puppet apply ======
276
277
  ERROR
277
278
  raise puppet_apply_error
278
279
  end
@@ -282,12 +283,12 @@ with exit code #{result.first['result']['exit_code']} (expected: #{acceptable_ex
282
283
  # @param command [String] The puppet command causing the error.
283
284
  # @param result [Array] The result struct containing the result
284
285
  def report_puppet_apply_change(command, result)
285
- puppet_apply_changes = <<-ERROR
286
- apply manifest expected no changes
287
- `#{command}`
288
- ====== Start output of Puppet apply with unexpected changes ======
289
- #{puppet_output(result)}
290
- ====== End output of Puppet apply with unexpected changes ======
286
+ puppet_apply_changes = <<~ERROR
287
+ apply manifest expected no changes
288
+ `#{command}`
289
+ ====== Start output of Puppet apply with unexpected changes ======
290
+ #{puppet_output(result)}
291
+ ====== End output of Puppet apply with unexpected changes ======
291
292
  ERROR
292
293
  raise puppet_apply_changes
293
294
  end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PuppetLitmus; end # rubocop:disable Style/Documentation
4
+
5
+ # helper methods for the litmus rake tasks
6
+ module PuppetLitmus::RakeHelper
7
+ DEFAULT_CONFIG_DATA ||= { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }.freeze
8
+ VALID_PROVISIONERS ||= %w[abs docker docker_exp vagrant vmpooler].freeze
9
+
10
+ # Gets a string representing the operating system and version.
11
+ #
12
+ # @param metadata [Hash] metadata to parse for operating system info
13
+ # @return [String] the operating system string with version info for use in provisioning.
14
+ def get_metadata_operating_systems(metadata)
15
+ return unless metadata.is_a?(Hash)
16
+ return unless metadata['operatingsystem_support'].is_a?(Array)
17
+
18
+ metadata['operatingsystem_support'].each do |os_info|
19
+ next unless os_info['operatingsystem'] && os_info['operatingsystemrelease']
20
+
21
+ os_name = case os_info['operatingsystem']
22
+ when 'Amazon', 'Archlinux', 'AIX', 'OSX'
23
+ next
24
+ when 'OracleLinux'
25
+ 'oracle'
26
+ when 'Windows'
27
+ 'win'
28
+ else
29
+ os_info['operatingsystem'].downcase
30
+ end
31
+
32
+ os_info['operatingsystemrelease'].each do |release|
33
+ version = case os_name
34
+ when 'ubuntu', 'osx'
35
+ release.sub('.', '')
36
+ when 'sles'
37
+ release.gsub(%r{ SP[14]}, '')
38
+ when 'win'
39
+ release = release.delete('.') if release.include? '8.1'
40
+ release.sub('Server', '').sub('10', '10-pro')
41
+ else
42
+ release
43
+ end
44
+
45
+ yield "#{os_name}-#{version.downcase}-x86_64".delete(' ')
46
+ end
47
+ end
48
+ end
49
+
50
+ # Executes a command on the test runner.
51
+ #
52
+ # @param command [String] command to execute.
53
+ # @return [Object] the standard out stream.
54
+ def run_local_command(command)
55
+ require 'open3'
56
+ stdout, stderr, status = Open3.capture3(command)
57
+ error_message = "Attempted to run\ncommand:'#{command}'\nstdout:#{stdout}\nstderr:#{stderr}"
58
+ raise error_message unless status.to_i.zero?
59
+
60
+ stdout
61
+ end
62
+
63
+ # Builds all the modules in a specified module
64
+ #
65
+ # @param source_folder [String] the folder to get the modules from
66
+ # @return [Array] an array of module tar's
67
+ def build_modules_in_folder(source_folder)
68
+ folder_list = Dir.entries(source_folder).reject { |f| File.directory? f }
69
+ module_tars = []
70
+ folder_list.each do |folder|
71
+ file = File.new(File.join(source_folder, folder))
72
+ next if File.symlink?(file)
73
+
74
+ opts = {}
75
+ opts[:module_dir] = file.path
76
+ opts[:'target-dir'] = File.join(Dir.pwd, 'pkg')
77
+ opts[:force] = true
78
+ # remove old build folder if exists, before we build afresh
79
+ FileUtils.rm_rf(builder.build_dir) if File.directory?(builder.build_dir)
80
+
81
+ # build_module
82
+ module_tar = build_module(opts)
83
+ module_tars.push(File.new(module_tar))
84
+ end
85
+ module_tars
86
+ end
87
+
88
+ def provision(provisioner, platform, inventory_vars)
89
+ require 'bolt_spec/run'
90
+ include BoltSpec::Run
91
+ raise "the provision module was not found in #{DEFAULT_CONFIG_DATA['modulepath']}, please amend the .fixtures.yml file" unless
92
+ File.directory?(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'provision'))
93
+
94
+ unless VALID_PROVISIONERS.include?(provisioner)
95
+ raise "Unknown provisioner '#{provisioner}', try #{VALID_PROVISIONERS.join('/')}"
96
+ end
97
+
98
+ params = if inventory_vars.nil?
99
+ { 'action' => 'provision', 'platform' => platform, 'inventory' => Dir.pwd }
100
+ else
101
+ { 'action' => 'provision', 'platform' => platform, 'inventory' => Dir.pwd, 'vars' => inventory_vars }
102
+ end
103
+ run_task("provision::#{provisioner}", 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
104
+ end
105
+
106
+ def provision_list(provision_hash, key)
107
+ provisioner = provision_hash[key]['provisioner']
108
+ inventory_vars = provision_hash[key]['vars']
109
+ # Splat the params into environment variables to pass to the provision task but only in this runspace
110
+ provision_hash[key]['params']&.each { |k, value| ENV[k.upcase] = value.to_s }
111
+ results = []
112
+ provision_hash[key]['images'].each do |image|
113
+ results << provision(provisioner, image, inventory_vars)
114
+ end
115
+ results
116
+ end
117
+
118
+ def tear_down_nodes(targets, inventory_hash)
119
+ require 'bolt_spec/run'
120
+ include BoltSpec::Run
121
+ config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
122
+ raise "the provision module was not found in #{config_data['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(config_data['modulepath'], 'provision'))
123
+
124
+ results = {}
125
+ targets.each do |node_name|
126
+ next if node_name == 'litmus_localhost'
127
+
128
+ result = tear_down(node_name, inventory_hash)
129
+ results[node_name] = result unless result == []
130
+ end
131
+ results
132
+ end
133
+
134
+ def tear_down(node_name, inventory_hash)
135
+ # how do we know what provisioner to use
136
+ node_facts = facts_from_node(inventory_hash, node_name)
137
+ return [] unless VALID_PROVISIONERS.include?(node_facts['provisioner'])
138
+
139
+ params = { 'action' => 'tear_down', 'node_name' => node_name, 'inventory' => Dir.pwd }
140
+ run_task("provision::#{node_facts['provisioner']}", 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil)
141
+ end
142
+
143
+ def install_agent(collection, targets, inventory_hash)
144
+ require 'bolt_spec/run'
145
+ include BoltSpec::Run
146
+ params = if collection.nil?
147
+ {}
148
+ else
149
+ { 'collection' => collection }
150
+ end
151
+ raise "puppet_agent was not found in #{DEFAULT_CONFIG_DATA['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'puppet_agent'))
152
+
153
+ run_task('puppet_agent::install', targets, params, config: DEFAULT_CONFIG_DATA, inventory: inventory_hash)
154
+ end
155
+
156
+ def configure_path(inventory_hash)
157
+ results = []
158
+ # fix the path on ssh_nodes
159
+ unless inventory_hash['groups'].select { |group| group['name'] == 'ssh_nodes' }.size.zero?
160
+ results = run_command('echo PATH="$PATH:/opt/puppetlabs/puppet/bin" > /etc/environment',
161
+ 'ssh_nodes', config: nil, inventory: inventory_hash)
162
+ end
163
+ results
164
+ end
165
+
166
+ def build_module(opts)
167
+ # old cli_way
168
+ # pdk_build_command = 'bundle exec pdk build --force'
169
+ # stdout, stderr, _status = Open3.capture3(pdk_build_command)
170
+ # raise "Failed to run 'pdk_build_command',#{stdout} and #{stderr}" if (stderr =~ %r{completed successfully}).nil?
171
+ require 'pdk/module/build'
172
+ require 'pdk/util'
173
+
174
+ builder = PDK::Module::Build.new(opts)
175
+ builder.build
176
+ end
177
+
178
+ def install_module(inventory_hash, target_node_name, module_tar)
179
+ require 'bolt_spec/run'
180
+ include BoltSpec::Run
181
+ target_nodes = find_targets(inventory_hash, target_node_name)
182
+ target_string = if target_node_name.nil?
183
+ 'all'
184
+ else
185
+ target_node_name
186
+ end
187
+ run_local_command("bundle exec bolt file upload \"#{module_tar}\" /tmp/#{File.basename(module_tar)} --nodes #{target_string} --inventoryfile inventory.yaml")
188
+ install_module_command = "puppet module install /tmp/#{File.basename(module_tar)}"
189
+ run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
190
+ end
191
+
192
+ def metadata_module_name
193
+ require 'json'
194
+ raise 'Could not find metadata.json' unless File.exist?(File.join(Dir.pwd, 'metadata.json'))
195
+
196
+ metadata = JSON.parse(File.read(File.join(Dir.pwd, 'metadata.json')))
197
+ raise 'Could not read module name from metadata.json' if metadata['name'].nil?
198
+
199
+ metadata['name']
200
+ end
201
+
202
+ def uninstall_module(inventory_hash, target_node_name, module_to_remove = nil)
203
+ require 'bolt_spec/run'
204
+ include BoltSpec::Run
205
+ module_name = module_to_remove || metadata_module_name
206
+ target_nodes = find_targets(inventory_hash, target_node_name)
207
+ install_module_command = "puppet module uninstall #{module_name}"
208
+ run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
209
+ end
210
+ end
@@ -1,100 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rspec/core/rake_task'
4
- require 'puppet_litmus'
5
- require 'bolt_spec/run'
6
- require 'open3'
7
- require 'pdk'
8
- require 'json'
9
- require 'parallel'
10
- require 'tty-spinner'
11
-
12
- # helper methods for the litmus rake tasks
13
- module LitmusRakeHelper
14
- # Gets a string representing the operating system and version.
15
- #
16
- # @param metadata [Hash] metadata to parse for operating system info
17
- # @return [String] the operating system string with version info for use in provisioning.
18
- def get_metadata_operating_systems(metadata)
19
- return unless metadata.is_a?(Hash)
20
- return unless metadata['operatingsystem_support'].is_a?(Array)
21
-
22
- metadata['operatingsystem_support'].each do |os_info|
23
- next unless os_info['operatingsystem'] && os_info['operatingsystemrelease']
24
-
25
- os_name = case os_info['operatingsystem']
26
- when 'Amazon', 'Archlinux', 'AIX', 'OSX'
27
- next
28
- when 'OracleLinux'
29
- 'oracle'
30
- when 'Windows'
31
- 'win'
32
- else
33
- os_info['operatingsystem'].downcase
34
- end
35
-
36
- os_info['operatingsystemrelease'].each do |release|
37
- version = case os_name
38
- when 'ubuntu', 'osx'
39
- release.sub('.', '')
40
- when 'sles'
41
- release.gsub(%r{ SP[14]}, '')
42
- when 'win'
43
- release = release.delete('.') if release.include? '8.1'
44
- release.sub('Server', '').sub('10', '10-pro')
45
- else
46
- release
47
- end
48
-
49
- yield "#{os_name}-#{version.downcase}-x86_64".delete(' ')
50
- end
51
- end
52
- end
53
-
54
- # Executes a command on the test runner.
55
- #
56
- # @param command [String] command to execute.
57
- # @return [Object] the standard out stream.
58
- def run_local_command(command)
59
- stdout, stderr, status = Open3.capture3(command)
60
- error_message = "Attempted to run\ncommand:'#{command}'\nstdout:#{stdout}\nstderr:#{stderr}"
61
- raise error_message unless status.to_i.zero?
62
-
63
- stdout
64
- end
65
-
66
- # Builds all the modules in a specified module
67
- #
68
- # @param source_folder [String] the folder to get the modules from
69
- # @return [Array] an array of module tar's
70
- def build_modules_in_folder(source_folder)
71
- require 'pdk/module/build'
72
- require 'pdk/util'
73
- folder_list = Dir.entries(source_folder).reject { |f| File.directory? f }
74
- module_tars = []
75
- folder_list.each do |folder|
76
- file = File.new(File.join(source_folder, folder))
77
- next if File.symlink?(file)
78
-
79
- opts = {}
80
- opts[:module_dir] = file.path
81
- opts[:'target-dir'] = File.join(Dir.pwd, 'pkg')
82
- opts[:force] = true
83
- builder = PDK::Module::Build.new(opts)
84
-
85
- # remove old build folder if exists, before we build afresh
86
- FileUtils.rm_rf(builder.build_dir) if File.directory?(builder.build_dir)
87
-
88
- # build_module
89
- module_tar = builder.build
90
- module_tars.push(File.new(module_tar))
91
- end
92
- module_tars
93
- end
94
- end
95
-
96
3
  namespace :litmus do
97
- include LitmusRakeHelper
4
+ require 'puppet_litmus/rake_helper'
5
+ include PuppetLitmus::RakeHelper
98
6
  # Prints all supported OSes from metadata.json file.
99
7
  desc 'print all supported OSes from metadata'
100
8
  task :metadata do
@@ -115,23 +23,43 @@ namespace :litmus do
115
23
  provision_hash = YAML.load_file('./provision.yaml')
116
24
  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?
117
25
 
26
+ Rake::Task['spec_prep'].invoke
27
+
118
28
  provisioner = provision_hash[args[:key]]['provisioner']
119
29
  inventory_vars = provision_hash[args[:key]]['vars']
120
30
  # Splat the params into environment variables to pass to the provision task but only in this runspace
121
- provision_hash[args[:key]]['params']&.each { |key, value| ENV[key.upcase] = value.to_s }
31
+ provision_hash[args[:key]]['params']&.each { |k, value| ENV[k.upcase] = value.to_s }
32
+ results = []
122
33
  failed_image_message = ''
123
34
  provision_hash[args[:key]]['images'].each do |image|
124
- # this is the only way to capture the stdout from the rake task, it will affect pry
125
- capture_rake_output = StringIO.new
126
- $stdout = capture_rake_output
127
- Rake::Task['litmus:provision'].invoke(provisioner, image, inventory_vars)
128
- if $stdout.string =~ %r{.status.=>.failure}
129
- failed_image_message += "=====\n#{image}\n#{$stdout.string}\n"
35
+ if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
36
+ progress = Thread.new do
37
+ loop do
38
+ printf '.'
39
+ sleep(10)
40
+ end
41
+ end
42
+ else
43
+ require 'tty-spinner'
44
+ spinner = TTY::Spinner.new("Provisioning #{image} using #{provisioner} provisioner.[:spinner]")
45
+ spinner.auto_spin
46
+ end
47
+ result = provision(provisioner, image, inventory_vars)
48
+
49
+ if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
50
+ Thread.kill(progress)
130
51
  else
131
- STDOUT.puts $stdout.string
52
+ spinner.success
132
53
  end
133
- Rake::Task['litmus:provision'].reenable
54
+
55
+ if result.first['status'] != 'success'
56
+ failed_image_message += "=====\n#{result.first['node']}\n#{result.first['result']['_output']}\n"
57
+ else
58
+ STDOUT.puts "#{result.first['result']['node_name']}, #{image}"
59
+ end
60
+ results << result
134
61
  end
62
+
135
63
  raise "Failed to provision with '#{provisioner}'\n #{failed_image_message}" unless failed_image_message.empty?
136
64
  end
137
65
 
@@ -141,21 +69,7 @@ namespace :litmus do
141
69
  # @param :platform [String] OS platform for container or VM to use.
142
70
  desc "provision container/VM - abs/docker/vagrant/vmpooler eg 'bundle exec rake 'litmus:provision[vmpooler, ubuntu-1604-x86_64]'"
143
71
  task :provision, [:provisioner, :platform, :inventory_vars] do |_task, args|
144
- include BoltSpec::Run
145
72
  Rake::Task['spec_prep'].invoke
146
- config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
147
- raise "the provision module was not found in #{config_data['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(config_data['modulepath'], 'provision'))
148
-
149
- unless %w[abs docker docker_exp vagrant vmpooler].include?(args[:provisioner])
150
- raise "Unknown provisioner '#{args[:provisioner]}', try abs/docker/docker_exp/vagrant/vmpooler"
151
- end
152
-
153
- params = if args[:inventory_vars].nil?
154
- { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd }
155
- else
156
- { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd, 'vars' => args[:inventory_vars] }
157
- end
158
-
159
73
  if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
160
74
  progress = Thread.new do
161
75
  loop do
@@ -164,10 +78,11 @@ namespace :litmus do
164
78
  end
165
79
  end
166
80
  else
81
+ require 'tty-spinner'
167
82
  spinner = TTY::Spinner.new("Provisioning #{args[:platform]} using #{args[:provisioner]} provisioner.[:spinner]")
168
83
  spinner.auto_spin
169
84
  end
170
- results = run_task("provision::#{args[:provisioner]}", 'localhost', params, config: config_data, inventory: nil)
85
+ results = provision(args[:provisioner], args[:platform], args[:inventory_vars])
171
86
  if results.first['status'] != 'success'
172
87
  raise "Failed provisioning #{args[:platform]} using #{args[:provisioner]}\n#{results.first}"
173
88
  end
@@ -193,17 +108,11 @@ namespace :litmus do
193
108
  exit 0
194
109
  end
195
110
  puts 'install_agent'
111
+ require 'bolt_spec/run'
196
112
  include BoltSpec::Run
197
113
  Rake::Task['spec_prep'].invoke
198
- config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
199
- params = if args[:collection].nil?
200
- {}
201
- else
202
- { 'collection' => args[:collection] }
203
- end
204
- raise "puppet_agent was not found in #{config_data['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(config_data['modulepath'], 'puppet_agent'))
205
-
206
- results = run_task('puppet_agent::install', targets, params, config: config_data, inventory: inventory_hash)
114
+
115
+ results = install_agent(args[:collection], targets, inventory_hash)
207
116
  results.each do |result|
208
117
  if result['status'] != 'success'
209
118
  command_to_run = "bolt task run puppet_agent::install --targets #{result['node']} --inventoryfile inventory.yaml --modulepath #{config_data['modulepath']}"
@@ -217,10 +126,7 @@ namespace :litmus do
217
126
  write_to_inventory_file(inventory_hash, 'inventory.yaml')
218
127
 
219
128
  # fix the path on ssh_nodes
220
- unless inventory_hash['groups'].select { |group| group['name'] == 'ssh_nodes' }.size.zero?
221
- results = run_command('echo PATH="$PATH:/opt/puppetlabs/puppet/bin" > /etc/environment',
222
- 'ssh_nodes', config: nil, inventory: inventory_hash)
223
- end
129
+ results = configure_path(inventory_hash)
224
130
 
225
131
  results.each do |result|
226
132
  if result['status'] != 'success'
@@ -253,6 +159,7 @@ namespace :litmus do
253
159
  module_tars.each do |module_tar|
254
160
  print "#{File.basename(module_tar)} "
255
161
  end
162
+ require 'bolt_spec/run'
256
163
  include BoltSpec::Run
257
164
  puts "\nSending"
258
165
  module_tars.each do |module_tar|
@@ -279,33 +186,18 @@ namespace :litmus do
279
186
  puts 'No targets found'
280
187
  exit 0
281
188
  end
282
- include BoltSpec::Run
283
- # old cli_way
284
- # pdk_build_command = 'bundle exec pdk build --force'
285
- # stdout, stderr, _status = Open3.capture3(pdk_build_command)
286
- # raise "Failed to run 'pdk_build_command',#{stdout} and #{stderr}" if (stderr =~ %r{completed successfully}).nil?
287
- require 'pdk/module/build'
288
- require 'pdk/util'
289
189
 
290
190
  opts = {}
291
191
  opts[:force] = true
292
- builder = PDK::Module::Build.new(opts)
293
- module_tar = builder.build
192
+ module_tar = build_module(opts)
294
193
  puts 'Built'
295
194
 
296
195
  # module_tar = Dir.glob('pkg/*.tar.gz').max_by { |f| File.mtime(f) }
297
196
  raise "Unable to find package in 'pkg/*.tar.gz'" if module_tar.nil?
298
197
 
299
- target_string = if args[:target_node_name].nil?
300
- 'all'
301
- else
302
- args[:target_node_name]
303
- end
304
- run_local_command("bundle exec bolt file upload \"#{module_tar}\" /tmp/#{File.basename(module_tar)} --nodes #{target_string} --inventoryfile inventory.yaml")
305
- install_module_command = "puppet module install /tmp/#{File.basename(module_tar)}"
306
- result = run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
198
+ result = install_module(inventory_hash, args[:target_node_name], module_tar)
307
199
 
308
- raise "Failed trying to run '#{install_module_command}' against inventory." unless result.is_a?(Array)
200
+ raise "Failed trying to run 'puppet module install /tmp/#{File.basename(module_tar)}' against inventory." unless result.is_a?(Array)
309
201
 
310
202
  result.each do |node|
311
203
  puts "#{node['node']} failed #{node['result']}" if node['status'] != 'success'
@@ -337,25 +229,14 @@ namespace :litmus do
337
229
  puts 'No targets found'
338
230
  exit 0
339
231
  end
340
- include BoltSpec::Run
341
232
  Rake::Task['spec_prep'].invoke
342
- config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
343
- raise "the provision module was not found in #{config_data['modulepath']}, please amend the .fixtures.yml file" unless File.directory?(File.join(config_data['modulepath'], 'provision'))
344
-
345
233
  bad_results = []
346
- targets.each do |node_name|
347
- next if node_name == 'litmus_localhost'
348
-
349
- # how do we know what provisioner to use
350
- node_facts = facts_from_node(inventory_hash, node_name)
351
- next unless %w[abs docker docker_exp vagrant vmpooler].include?(node_facts['provisioner'])
352
-
353
- params = { 'action' => 'tear_down', 'node_name' => node_name, 'inventory' => Dir.pwd }
354
- result = run_task("provision::#{node_facts['provisioner']}", 'localhost', params, config: config_data, inventory: nil)
234
+ results = tear_down_nodes(targets, inventory_hash)
235
+ results.each do |node, result|
355
236
  if result.first['status'] != 'success'
356
- bad_results << "#{node_name}, #{result.first['result']['_error']['msg']}"
237
+ bad_results << "#{node}, #{result.first['result']['_error']['msg']}"
357
238
  else
358
- print "#{node_name}, "
239
+ puts "#{node}: #{result.first['status']}"
359
240
  end
360
241
  end
361
242
  puts ''
@@ -366,9 +247,44 @@ namespace :litmus do
366
247
  end
367
248
  end
368
249
 
250
+ # Uninstall the puppet module under test on a collection of nodes
251
+ #
252
+ # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
253
+ # @param :module_name [String] module name to be uninstalled
254
+ desc 'uninstall_module - uninstall module'
255
+ task :uninstall_module, [:target_node_name, :module_name] do |_task, args|
256
+ inventory_hash = inventory_hash_from_inventory_file
257
+ target_nodes = find_targets(inventory_hash, args[:target_node_name])
258
+ if target_nodes.empty?
259
+ puts 'No targets found'
260
+ exit 0
261
+ end
262
+
263
+ result = uninstall_module(inventory_hash, args[:target_node_name], args[:module_name])
264
+
265
+ raise "Failed trying to run 'puppet module uninstall #{module_name}' against inventory." unless result.is_a?(Array)
266
+
267
+ result.each do |node|
268
+ puts "#{node['node']} failed #{node['result']}" if node['status'] != 'success'
269
+ end
270
+
271
+ puts 'Uninstalled'
272
+ end
273
+
274
+ # Reinstall the puppet module under test on a collection of nodes
275
+ #
276
+ # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
277
+ desc 'reinstall_module - reinstall module'
278
+ task :reinstall_module, [:target_node_name] do |_task, args|
279
+ Rake::Task['litmus:uninstall_module'].invoke(args[:target_node_name])
280
+ Rake::Task['litmus:install_module'].invoke(args[:target_node_name])
281
+ end
282
+
369
283
  namespace :acceptance do
370
- include PuppetLitmus::InventoryManipulation
284
+ require 'rspec/core/rake_task'
371
285
  if File.file?('inventory.yaml')
286
+ require 'puppet_litmus/inventory_manipulation'
287
+ include PuppetLitmus::InventoryManipulation
372
288
  inventory_hash = inventory_hash_from_inventory_file
373
289
  targets = find_targets(inventory_hash, nil)
374
290
 
@@ -406,6 +322,7 @@ namespace :litmus do
406
322
  end
407
323
  end
408
324
 
325
+ require 'parallel'
409
326
  results = Parallel.map(payloads) do |title, test, options|
410
327
  env = options[:env].nil? ? {} : options[:env]
411
328
  stdout, stderr, status = Open3.capture3(env, test)
@@ -421,6 +338,7 @@ namespace :litmus do
421
338
  end
422
339
  Thread.kill(progress)
423
340
  else
341
+ require 'tty-spinner'
424
342
  spinners = TTY::Spinner::Multi.new("[:spinner] Running against #{targets.size} targets.")
425
343
  payloads.each do |title, test, options|
426
344
  env = options[:env].nil? ? {} : options[:env]
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Helper methods for testing puppet content
4
+ module PuppetLitmus
5
+ extend PuppetLitmus::InventoryManipulation
6
+
7
+ def self.configure!
8
+ require 'serverspec'
9
+
10
+ RSpec.configure do |config|
11
+ config.include PuppetLitmus
12
+ end
13
+
14
+ if ENV['TARGET_HOST'].nil? || ENV['TARGET_HOST'] == 'localhost'
15
+ puts 'Running tests against this machine !'
16
+ if Gem.win_platform?
17
+ set :backend, :cmd
18
+ else
19
+ set :backend, :exec
20
+ end
21
+ else
22
+ # load inventory
23
+ inventory_hash = inventory_hash_from_inventory_file
24
+ node_config = config_from_node(inventory_hash, ENV['TARGET_HOST'])
25
+
26
+ if target_in_group(inventory_hash, ENV['TARGET_HOST'], 'docker_nodes')
27
+ host = ENV['TARGET_HOST']
28
+ set :backend, :docker
29
+ set :docker_container, host
30
+ elsif target_in_group(inventory_hash, ENV['TARGET_HOST'], 'ssh_nodes')
31
+ set :backend, :ssh
32
+ options = Net::SSH::Config.for(host)
33
+ options[:user] = node_config.dig('ssh', 'user') unless node_config.dig('ssh', 'user').nil?
34
+ options[:port] = node_config.dig('ssh', 'port') unless node_config.dig('ssh', 'port').nil?
35
+ options[:keys] = node_config.dig('ssh', 'private-key') unless node_config.dig('ssh', 'private-key').nil?
36
+ options[:password] = node_config.dig('ssh', 'password') unless node_config.dig('ssh', 'password').nil?
37
+ # Support both net-ssh 4 and 5.
38
+ # rubocop:disable Metrics/BlockNesting
39
+ options[:verify_host_key] = if node_config.dig('ssh', 'host-key-check').nil?
40
+ # Fall back to SSH behavior. This variable will only be set in net-ssh 5.3+.
41
+ if @strict_host_key_checking.nil? || @strict_host_key_checking
42
+ Net::SSH::Verifiers::Always.new
43
+ else
44
+ # SSH's behavior with StrictHostKeyChecking=no: adds new keys to known_hosts.
45
+ # If known_hosts points to /dev/null, then equivalent to :never where it
46
+ # accepts any key beacuse they're all new.
47
+ Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
48
+ end
49
+ elsif node_config.dig('ssh', 'host-key-check')
50
+ if defined?(Net::SSH::Verifiers::Always)
51
+ Net::SSH::Verifiers::Always.new
52
+ else
53
+ Net::SSH::Verifiers::Secure.new
54
+ end
55
+ elsif defined?(Net::SSH::Verifiers::Never)
56
+ Net::SSH::Verifiers::Never.new
57
+ else
58
+ Net::SSH::Verifiers::Null.new
59
+ end
60
+ # rubocop:enable Metrics/BlockNesting
61
+ host = if ENV['TARGET_HOST'].include?(':')
62
+ ENV['TARGET_HOST'].split(':').first
63
+ else
64
+ ENV['TARGET_HOST']
65
+ end
66
+ set :host, options[:host_name] || host
67
+ set :ssh_options, options
68
+ set :request_pty, true
69
+ elsif target_in_group(inventory_hash, ENV['TARGET_HOST'], 'winrm_nodes')
70
+ require 'winrm'
71
+
72
+ set :backend, :winrm
73
+ set :os, family: 'windows'
74
+ user = node_config.dig('winrm', 'user') unless node_config.dig('winrm', 'user').nil?
75
+ pass = node_config.dig('winrm', 'password') unless node_config.dig('winrm', 'password').nil?
76
+ endpoint = "http://#{ENV['TARGET_HOST']}:5985/wsman"
77
+
78
+ opts = {
79
+ user: user,
80
+ password: pass,
81
+ endpoint: endpoint,
82
+ operation_timeout: 300,
83
+ }
84
+
85
+ winrm = WinRM::Connection.new opts
86
+ Specinfra.configuration.winrm = winrm
87
+ end
88
+ end
89
+ end
90
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # version of this gem
4
4
  module PuppetLitmus
5
- VERSION ||= '0.12.0'
5
+ VERSION ||= '0.13.0'
6
6
  end
@@ -87,7 +87,7 @@ RSpec.describe PuppetLitmus::PuppetHelpers do
87
87
 
88
88
  describe '.run_shell' do
89
89
  let(:command_to_run) { "puts 'doot'" }
90
- let(:result) { ['result' => { 'exit_code' => 0, 'stdout' => nil, 'stderr' => nil }] }
90
+ let(:result) { ['result' => { 'exit_code' => 0, 'exit_status' => 0, 'stdout' => nil, 'stderr' => nil }] }
91
91
  let(:inventory_hash) { { 'groups' => [{ 'name' => 'ssh_nodes', 'nodes' => [{ 'name' => 'some.host' }] }] } }
92
92
  let(:localhost_inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'litmus_localhost', 'config' => { 'transport' => 'local' } }] }] } }
93
93
 
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ load File.expand_path('../../../lib/puppet_litmus/rake_helper.rb', __dir__)
6
+
7
+ RSpec.describe PuppetLitmus::RakeHelper do
8
+ context 'with provision_list' do
9
+ let(:provision_hash) { { 'default' => { 'provisioner' => 'docker', 'images' => ['waffleimage/centos7'] } } }
10
+ let(:results) { [] }
11
+
12
+ it 'calls function' do
13
+ expect(described_class).to receive(:provision).with('docker', 'waffleimage/centos7', nil).and_return(results)
14
+ described_class.provision_list(provision_hash, 'default')
15
+ end
16
+ end
17
+
18
+ context 'with provision' do
19
+ let(:provision_hash) { { 'default' => { 'provisioner' => 'docker', 'images' => ['waffleimage/centos7'] } } }
20
+ let(:results) { [] }
21
+ let(:params) { { 'action' => 'provision', 'platform' => 'waffleimage/centos7', 'inventory' => Dir.pwd } }
22
+
23
+ it 'calls function' do
24
+ allow(File).to receive(:directory?).and_call_original
25
+ allow(File).to receive(:directory?).with(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'provision')).and_return(true)
26
+ allow_any_instance_of(BoltSpec::Run).to receive(:run_task).with('provision::docker', 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil).and_return(results)
27
+ described_class.provision('docker', 'waffleimage/centos7', nil)
28
+ end
29
+ end
30
+
31
+ context 'with tear_down' do
32
+ let(:inventory_hash) do
33
+ { 'groups' =>
34
+ [{ 'name' => 'ssh_nodes', 'nodes' =>
35
+ [{ 'name' => 'some.host', 'facts' => { 'provisioner' => 'docker', 'container_name' => 'foo', 'platform' => 'some.host' } }] }] }
36
+ end
37
+ let(:targets) { ['some.host'] }
38
+ let(:params) { { 'action' => 'tear_down', 'node_name' => 'some.host', 'inventory' => Dir.pwd } }
39
+
40
+ it 'calls function' do
41
+ allow(File).to receive(:directory?).with(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'provision')).and_return(true)
42
+ allow_any_instance_of(BoltSpec::Run).to receive(:run_task).with('provision::docker', 'localhost', params, config: DEFAULT_CONFIG_DATA, inventory: nil).and_return([])
43
+ described_class.tear_down_nodes(targets, inventory_hash)
44
+ end
45
+ end
46
+
47
+ context 'with install_agent' do
48
+ let(:inventory_hash) do
49
+ { 'groups' =>
50
+ [{ 'name' => 'ssh_nodes', 'nodes' =>
51
+ [{ 'name' => 'some.host', 'facts' => { 'provisioner' => 'docker', 'container_name' => 'foo', 'platform' => 'some.host' } }] }] }
52
+ end
53
+ let(:targets) { ['some.host'] }
54
+ let(:params) { { 'collection' => 'puppet6' } }
55
+
56
+ it 'calls function' do
57
+ allow(File).to receive(:directory?).with(File.join(DEFAULT_CONFIG_DATA['modulepath'], 'puppet_agent')).and_return(true)
58
+ allow_any_instance_of(BoltSpec::Run).to receive(:run_task).with('puppet_agent::install', targets, params, config: DEFAULT_CONFIG_DATA, inventory: inventory_hash).and_return([])
59
+ described_class.install_agent('puppet6', targets, inventory_hash)
60
+ end
61
+ end
62
+
63
+ context 'with install_module' do
64
+ let(:inventory_hash) do
65
+ { 'groups' =>
66
+ [{ 'name' => 'ssh_nodes', 'nodes' =>
67
+ [{ 'name' => 'some.host', 'facts' => { 'provisioner' => 'docker', 'container_name' => 'foo', 'platform' => 'some.host' } }] }] }
68
+ end
69
+ let(:module_tar) { '/tmp/foo.tar.gz' }
70
+ let(:targets) { ['some.host'] }
71
+ let(:install_module_command) { "puppet module install /tmp/#{File.basename(module_tar)}" }
72
+
73
+ it 'calls function' do
74
+ allow(Open3).to receive(:capture3).with("bundle exec bolt file upload \"#{module_tar}\" /tmp/#{File.basename(module_tar)} --nodes all --inventoryfile inventory.yaml")
75
+ .and_return(['success', '', 0])
76
+ allow_any_instance_of(BoltSpec::Run).to receive(:run_command).with(install_module_command, targets, config: nil, inventory: inventory_hash).and_return([])
77
+ described_class.install_module(inventory_hash, nil, module_tar)
78
+ end
79
+ end
80
+
81
+ context 'with uninstall module' do
82
+ let(:inventory_hash) do
83
+ { 'groups' =>
84
+ [{ 'name' => 'ssh_nodes', 'nodes' =>
85
+ [{ 'name' => 'some.host', 'facts' => { 'provisioner' => 'docker', 'container_name' => 'foo', 'platform' => 'some.host' } }] }] }
86
+ end
87
+ let(:targets) { ['some.host'] }
88
+ let(:uninstall_module_command) { 'puppet module uninstall foo-bar' }
89
+
90
+ it 'uninstalls module' do
91
+ allow_any_instance_of(BoltSpec::Run).to receive(:run_command).with(uninstall_module_command, targets, config: nil, inventory: inventory_hash).and_return([])
92
+ expect(described_class).to receive(:metadata_module_name).and_return('foo-bar')
93
+ described_class.uninstall_module(inventory_hash, nil)
94
+ end
95
+
96
+ it 'and custom name' do
97
+ allow_any_instance_of(BoltSpec::Run).to receive(:run_command).with(uninstall_module_command, targets, config: nil, inventory: inventory_hash).and_return([])
98
+ described_class.uninstall_module(inventory_hash, nil, 'foo-bar')
99
+ end
100
+ end
101
+
102
+ context 'with module name' do
103
+ let(:metadata) { '{ "name" : "foo-bar" }' }
104
+
105
+ it 'reads module name' do
106
+ allow(File).to receive(:exist?).with(File.join(Dir.pwd, 'metadata.json')).and_return(true)
107
+ allow(File).to receive(:read).with(File.join(Dir.pwd, 'metadata.json')).and_return(metadata)
108
+ name = described_class.metadata_module_name
109
+ expect(name).to eq('foo-bar')
110
+ end
111
+ end
112
+ 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.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-15 00:00:00.000000000 Z
11
+ date: 2019-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bolt
@@ -90,6 +90,34 @@ dependencies:
90
90
  - - "<"
91
91
  - !ruby/object:Gem::Version
92
92
  version: 2.0.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: parallel
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ type: :runtime
101
+ prerelease: false
102
+ version_requirements: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ - !ruby/object:Gem::Dependency
108
+ name: rspec
109
+ requirement: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ type: :runtime
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
93
121
  description: " Providing a simple command line tool for puppet content creators,
94
122
  to enable simple and complex test deployments.\n"
95
123
  email:
@@ -103,13 +131,16 @@ files:
103
131
  - lib/puppet_litmus.rb
104
132
  - lib/puppet_litmus/inventory_manipulation.rb
105
133
  - lib/puppet_litmus/puppet_helpers.rb
134
+ - lib/puppet_litmus/rake_helper.rb
106
135
  - lib/puppet_litmus/rake_tasks.rb
136
+ - lib/puppet_litmus/spec_helper_acceptance.rb
107
137
  - lib/puppet_litmus/version.rb
108
138
  - spec/data/doot.tar.gz
109
139
  - spec/data/inventory.yaml
110
140
  - spec/data/jim.yaml
111
141
  - spec/lib/puppet_litmus/inventory_manipulation_spec.rb
112
142
  - spec/lib/puppet_litmus/puppet_helpers_spec.rb
143
+ - spec/lib/puppet_litmus/rake_helper_spec.rb
113
144
  - spec/lib/puppet_litmus/rake_tasks_spec.rb
114
145
  - spec/lib/puppet_litmus/version_spec.rb
115
146
  - spec/spec_helper.rb
@@ -143,6 +174,7 @@ test_files:
143
174
  - spec/data/jim.yaml
144
175
  - spec/lib/puppet_litmus/inventory_manipulation_spec.rb
145
176
  - spec/lib/puppet_litmus/puppet_helpers_spec.rb
177
+ - spec/lib/puppet_litmus/rake_helper_spec.rb
146
178
  - spec/lib/puppet_litmus/rake_tasks_spec.rb
147
179
  - spec/lib/puppet_litmus/version_spec.rb
148
180
  - spec/spec_helper.rb