puppet_litmus 0.9.1 → 0.10.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: bc193f9e3e7b23027e022082d77a4349e4db737fc36638d0ca8d9dca433d776d
4
- data.tar.gz: 57e68de10c7c77f2b7059163e6ebd1b66852f058e203d3ce7a2d9656f1eb7bd7
3
+ metadata.gz: 2b4b8f9d03595ac86920511bc3ec0429c34e99ebb54fce2e0dd80bce3d233145
4
+ data.tar.gz: c4a3bd340f4e215faa647111b6ba933d5669a43e4c06474ab4bc41766fb36235
5
5
  SHA512:
6
- metadata.gz: f1b37b780a30f7cfca61513debb0d3931ee68524e72f25e4c2c963feeee4012ab56fc4dc7e32717f20de39d15cbefd076198f48659f227bd5bc98134280142cd
7
- data.tar.gz: 6b910d580dbc673723f5cb2a0bcaca27f5b88462ffabf5190590c9d0dac3ac5efa18735dada0ea8831a59bf52121763a787e31da4d63af6bc9f4dcd1885302aa
6
+ metadata.gz: 848d4c8ea4ff3b7b6e02f1404cbbd255d847a259fab02db44032b3982127c5c9a0358366557454f03a85645eb4e9a2ef35bc0e0da90d5fae2d68fb2094912b5d
7
+ data.tar.gz: 85195c4df6ad10c37290acaba4d14cd4cb2d31950e8095a7afc5104e1a9d3050912dd4ff4a28b6bdcc90b3ff9cc7a956e5b0e1342bad4715ced75542ea0836c4
@@ -18,6 +18,25 @@ module PuppetLitmus::InventoryManipulation
18
18
  inventory_hash
19
19
  end
20
20
 
21
+ # Provide a default hash for executing against localhost
22
+ #
23
+ # @return [Hash] inventory.yaml hash containing only an entry for localhost
24
+ def localhost_inventory_hash
25
+ {
26
+ 'groups' => [
27
+ {
28
+ 'name' => 'local',
29
+ 'nodes' => [
30
+ {
31
+ 'name' => 'litmus_localhost',
32
+ 'config' => { 'transport' => 'local' },
33
+ },
34
+ ],
35
+ },
36
+ ],
37
+ }
38
+ end
39
+
21
40
  # Finds targets to perform operations on from an inventory hash.
22
41
  #
23
42
  # @param inventory_hash [Hash] hash of the inventory.yaml file
@@ -51,6 +70,15 @@ module PuppetLitmus::InventoryManipulation
51
70
  exists
52
71
  end
53
72
 
73
+ # Determines if a node_name exists in the inventory_hash.
74
+ #
75
+ # @param inventory_hash [Hash] hash of the inventory.yaml file
76
+ # @param node_name [String] node to locate in the group
77
+ # @return [Boolean] true if node_name exists in the inventory_hash.
78
+ def target_in_inventory?(inventory_hash, node_name)
79
+ find_targets(inventory_hash, nil).include?(node_name)
80
+ end
81
+
54
82
  # Finds a config hash in the inventory hash by searching for a node name.
55
83
  #
56
84
  # @param inventory_hash [Hash] hash of the inventory.yaml file
@@ -83,6 +111,22 @@ module PuppetLitmus::InventoryManipulation
83
111
  raise "No facts were found for #{node_name}"
84
112
  end
85
113
 
114
+ # Finds a var hash in the inventory hash by searching for a node name.
115
+ #
116
+ # @param inventory_hash [Hash] hash of the inventory.yaml file
117
+ # @param node_name [String] node to locate in the group
118
+ # @return [Hash] vars for node of name node_name
119
+ def vars_from_node(inventory_hash, node_name)
120
+ inventory_hash['groups'].each do |group|
121
+ group['nodes'].each do |node|
122
+ if node['name'] == node_name
123
+ return node['vars']
124
+ end
125
+ end
126
+ end
127
+ {}
128
+ end
129
+
86
130
  # Adds a node to a group specified, if group_name exists in inventory hash.
87
131
  #
88
132
  # @param inventory_hash [Hash] hash of the inventory.yaml file
@@ -74,32 +74,6 @@ namespace :litmus do
74
74
  end
75
75
  end
76
76
 
77
- # DEPRECATED - Provisions all supported OSes with provisioner eg 'bundle exec rake litmus:provision_from_metadata['vmpooler']'.
78
- #
79
- # @param :provisioner [String] provisioner to use in provisioning all OSes.
80
- desc "DEPRECATED: provision_from_metadata task is deprecated.
81
- Provision all supported OSes with provisioner eg 'bundle exec rake 'litmus:provision_from_metadata'"
82
- task :provision_from_metadata, [:provisioner] do |_task, args|
83
- metadata = JSON.parse(File.read('metadata.json'))
84
- get_metadata_operating_systems(metadata) do |os_and_version|
85
- puts os_and_version
86
- include BoltSpec::Run
87
- Rake::Task['spec_prep'].invoke
88
- config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
89
- 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'))
90
-
91
- params = { 'action' => 'provision', 'platform' => os_and_version, 'inventory' => Dir.pwd }
92
- results = run_task("provision::#{args[:provisioner]}", 'localhost', params, config: config_data, inventory: nil)
93
- results.each do |result|
94
- if result['status'] != 'success'
95
- puts "Failed on #{result['node']}\n#{result}"
96
- else
97
- puts "Provisioned #{result['result']['node_name']}"
98
- end
99
- end
100
- end
101
- end
102
-
103
77
  # Provisions a list of OSes from provision.yaml file e.g. 'bundle exec rake litmus:provision_list[default]'.
104
78
  #
105
79
  # @param :key [String] key that maps to a value for a provisioner and an image to be used for each OS provisioned.
@@ -107,6 +81,7 @@ namespace :litmus do
107
81
  task :provision_list, [:key] do |_task, args|
108
82
  provision_hash = YAML.load_file('./provision.yaml')
109
83
  provisioner = provision_hash[args[:key]]['provisioner']
84
+ inventory_vars = provision_hash[args[:key]]['vars']
110
85
  # Splat the params into environment variables to pass to the provision task but only in this runspace
111
86
  provision_hash[args[:key]]['params']&.each { |key, value| ENV[key.upcase] = value.to_s }
112
87
  failed_image_message = ''
@@ -114,7 +89,7 @@ namespace :litmus do
114
89
  # this is the only way to capture the stdout from the rake task, it will affect pry
115
90
  capture_rake_output = StringIO.new
116
91
  $stdout = capture_rake_output
117
- Rake::Task['litmus:provision'].invoke(provisioner, image)
92
+ Rake::Task['litmus:provision'].invoke(provisioner, image, inventory_vars)
118
93
  if $stdout.string =~ %r{.status.=>.failure}
119
94
  failed_image_message += "=====\n#{image}\n#{$stdout.string}\n"
120
95
  else
@@ -130,30 +105,43 @@ namespace :litmus do
130
105
  # @param :provisioner [String] provisioner to use in provisioning given platform.
131
106
  # @param :platform [String] OS platform for container or VM to use.
132
107
  desc "provision container/VM - abs/docker/vagrant/vmpooler eg 'bundle exec rake 'litmus:provision[vmpooler, ubuntu-1604-x86_64]'"
133
- task :provision, [:provisioner, :platform] do |_task, args|
108
+ task :provision, [:provisioner, :platform, :inventory_vars] do |_task, args|
134
109
  include BoltSpec::Run
135
110
  Rake::Task['spec_prep'].invoke
136
111
  config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
137
112
  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'))
138
113
 
139
114
  unless %w[abs docker docker_exp vagrant vmpooler].include?(args[:provisioner])
140
- raise "Unknown provisioner '#{args[:provisioner]}', try abs/docker/vagrant/vmpooler"
115
+ raise "Unknown provisioner '#{args[:provisioner]}', try abs/docker/docker_exp/vagrant/vmpooler"
141
116
  end
142
117
 
143
- params = { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd }
144
- spinner = if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
145
- TTY::Spinner.new(':spinner', frames: ['.'], interval: 0.1)
146
- else
147
- TTY::Spinner.new("Provisioning #{args[:platform]} using #{args[:provisioner]} provisioner.[:spinner]")
148
- end
149
- spinner.auto_spin
118
+ params = if args[:inventory_vars].nil?
119
+ { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd }
120
+ else
121
+ { 'action' => 'provision', 'platform' => args[:platform], 'inventory' => Dir.pwd, 'vars' => args[:inventory_vars] }
122
+ end
123
+
124
+ if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
125
+ progress = Thread.new do
126
+ loop do
127
+ printf '.'
128
+ sleep(10)
129
+ end
130
+ end
131
+ else
132
+ spinner = TTY::Spinner.new("Provisioning #{args[:platform]} using #{args[:provisioner]} provisioner.[:spinner]")
133
+ spinner.auto_spin
134
+ end
150
135
  results = run_task("provision::#{args[:provisioner]}", 'localhost', params, config: config_data, inventory: nil)
151
136
  if results.first['status'] != 'success'
152
- spinner.error
153
137
  raise "Failed provisioning #{args[:platform]} using #{args[:provisioner]}\n#{results.first}"
154
138
  end
155
139
 
156
- spinner.success
140
+ if (ENV['CI'] == 'true') || !ENV['DISTELLI_BUILDNUM'].nil?
141
+ Thread.kill(progress)
142
+ else
143
+ spinner.success
144
+ end
157
145
  puts "#{results.first['result']['node_name']}, #{args[:platform]}"
158
146
  end
159
147
 
@@ -189,7 +177,10 @@ namespace :litmus do
189
177
  end
190
178
 
191
179
  # fix the path on ssh_nodes
192
- results = run_command('echo PATH="$PATH:/opt/puppetlabs/puppet/bin" > /etc/environment', 'ssh_nodes', config: nil, inventory: inventory_hash) unless inventory_hash['groups'].select { |group| group['name'] == 'ssh_nodes' }.size.zero? # rubocop:disable Metrics/LineLength
180
+ unless inventory_hash['groups'].select { |group| group['name'] == 'ssh_nodes' }.size.zero?
181
+ results = run_command('echo PATH="$PATH:/opt/puppetlabs/puppet/bin" > /etc/environment',
182
+ 'ssh_nodes', config: nil, inventory: inventory_hash)
183
+ end
193
184
  results.each do |result|
194
185
  if result['status'] != 'success'
195
186
  puts "Failed on #{result['node']}\n#{result}"
@@ -197,58 +188,6 @@ namespace :litmus do
197
188
  end
198
189
  end
199
190
 
200
- # Install puppet enterprise - for internal puppet employees only - Requires an el7 provisioned machine - experimental feature [:target_node_name]'
201
- #
202
- # @param :target_node_name [Array] nodes on which to install puppet agent.
203
- desc 'install puppet enterprise - for internal puppet employees only - Requires an el7 provisioned machine - experimental feature [:target_node_name]'
204
- task :install_pe, [:target_node_name] do |_task, args|
205
- inventory_hash = inventory_hash_from_inventory_file
206
- target_nodes = find_targets(inventory_hash, args[:target_node_name])
207
- if target_nodes.empty?
208
- puts 'No targets found'
209
- exit 0
210
- end
211
- puts 'install_pe'
212
- include BoltSpec::Run
213
- Rake::Task['spec_prep'].invoke
214
- config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
215
-
216
- puts 'Setting up parameters'
217
-
218
- PE_RELEASE = 2019.0
219
- pe_latest_cmd = "curl http://enterprise.delivery.puppetlabs.net/#{PE_RELEASE}/ci-ready/LATEST"
220
- pe_latest = run_command(pe_latest_cmd, target_nodes, config: config_data, inventory: inventory_hash)
221
- pe_latest_string = pe_latest[0]['result']['stdout'].delete("\n")
222
- PE_FILE_NAME = "puppet-enterprise-#{pe_latest_string}-el-7-x86_64"
223
- TAR_FILE = "#{PE_FILE_NAME}.tar"
224
- DOWNLOAD_URL = "http://enterprise.delivery.puppetlabs.net/#{PE_RELEASE}/ci-ready/#{TAR_FILE}"
225
-
226
- puts 'Initiating PE download'
227
-
228
- # Download PE
229
- download_pe_cmd = "wget -q #{DOWNLOAD_URL}"
230
- run_command(download_pe_cmd, target_nodes, config: config_data, inventory: inventory_hash)
231
-
232
- puts 'PE successfully downloaded, running installer (this may take 5 or so minutes, please be patient)'
233
-
234
- # Install PE
235
- untar_cmd = "tar xvf #{TAR_FILE}"
236
- run_command(untar_cmd, target_nodes, config: config_data, inventory: inventory_hash)
237
- puts run_command("cd #{PE_FILE_NAME} && 1 | ./puppet-enterprise-installer", target_nodes, config: nil, inventory: inventory_hash)[0]['result']['stdout']
238
-
239
- puts 'Autosigning Certificates'
240
-
241
- # Set Autosign
242
- autosign_cmd = "echo 'autosign = true' >> /etc/puppetlabs/puppet/puppet.conf"
243
- run_command(autosign_cmd, target_nodes, config: config_data, inventory: inventory_hash)
244
-
245
- puts 'Finishing installation with a Puppet Agent run'
246
-
247
- run_command('puppet agent -t', target_nodes, config: config_data, inventory: inventory_hash)
248
-
249
- puts 'PE Installation is now complete'
250
- end
251
-
252
191
  # Install the puppet module under test on a collection of nodes
253
192
  #
254
193
  # @param :target_node_name [Array] nodes on which to install a puppet module for testing.
@@ -283,15 +222,13 @@ namespace :litmus do
283
222
  run_local_command("bundle exec bolt file upload \"#{module_tar}\" /tmp/#{File.basename(module_tar)} --nodes #{target_string} --inventoryfile inventory.yaml")
284
223
  install_module_command = "puppet module install /tmp/#{File.basename(module_tar)}"
285
224
  result = run_command(install_module_command, target_nodes, config: nil, inventory: inventory_hash)
286
- # rubocop:disable Style/GuardClause
287
- if result.is_a?(Array)
288
- result.each do |node|
289
- puts "#{node['node']} failed #{node['result']}" if node['status'] != 'success'
290
- end
291
- else
292
- raise "Failed trying to run '#{install_module_command}' against inventory."
225
+
226
+ raise "Failed trying to run '#{install_module_command}' against inventory." unless result.is_a?(Array)
227
+
228
+ result.each do |node|
229
+ puts "#{node['node']} failed #{node['result']}" if node['status'] != 'success'
293
230
  end
294
- # rubocop:enable Style/GuardClause
231
+
295
232
  puts 'Installed'
296
233
  end
297
234
 
@@ -325,6 +262,8 @@ namespace :litmus do
325
262
 
326
263
  bad_results = []
327
264
  targets.each do |node_name|
265
+ next if node_name == 'litmus_localhost'
266
+
328
267
  # how do we know what provisioner to use
329
268
  node_facts = facts_from_node(inventory_hash, node_name)
330
269
  next unless %w[abs docker docker_exp vagrant vmpooler].include?(node_facts['provisioner'])
@@ -361,7 +300,7 @@ namespace :litmus do
361
300
  payloads = []
362
301
  # Generate list of targets to provision
363
302
  targets.each do |target|
364
- test = 'bundle exec bundle exec rspec ./spec/acceptance --format progress'
303
+ test = 'bundle exec rspec ./spec/acceptance --format progress'
365
304
  title = "#{target}, #{facts_from_node(inventory_hash, target)['platform']}"
366
305
  options = {
367
306
  env: {
@@ -446,6 +385,8 @@ namespace :litmus do
446
385
 
447
386
  targets.each do |target|
448
387
  desc "Run serverspec against #{target}"
388
+ next if target == 'litmus_localhost'
389
+
449
390
  RSpec::Core::RakeTask.new(target.to_sym) do |t|
450
391
  t.pattern = 'spec/acceptance/**{,/*/**}/*_spec.rb'
451
392
  ENV['TARGET_HOST'] = target
@@ -9,7 +9,7 @@ module PuppetLitmus::Serverspec
9
9
  # @return [Boolean] The result of the 2 apply manifests.
10
10
  def idempotent_apply(manifest)
11
11
  manifest_file_location = create_manifest_file(manifest)
12
- apply_manifest(nil, catch_failures: true, manifest_file_location: manifest_file_location)
12
+ apply_manifest(nil, expect_failures: false, manifest_file_location: manifest_file_location)
13
13
  apply_manifest(nil, catch_changes: true, manifest_file_location: manifest_file_location)
14
14
  end
15
15
 
@@ -24,8 +24,10 @@ module PuppetLitmus::Serverspec
24
24
  #
25
25
  # @param manifest [String] puppet manifest code to be applied.
26
26
  # @param opts [Hash] Alters the behaviour of the command. Valid options are:
27
- # :catch_changes [Boolean] exit status of 1 if there were changes.
28
- # :expect_failures [Boolean] doesnt return an exit code of non-zero if the apply failed.
27
+ # :catch_changes [Boolean] (false) We're after idempotency so allow exit code 0 only.
28
+ # :expect_changes [Boolean] (false) We're after changes specifically so allow exit code 2 only.
29
+ # :catch_failures [Boolean] (false) We're after only complete success so allow exit codes 0 and 2 only.
30
+ # :expect_failures [Boolean] (false) We're after failures specifically so allow exit codes 1, 4, and 6 only.
29
31
  # :manifest_file_location [Path] The place on the target system.
30
32
  # :hiera_config [Path] The path to the hiera.yaml configuration on the runner.
31
33
  # :prefix_command [String] prefixes the puppet apply command; eg "export LANGUAGE='ja'".
@@ -35,25 +37,47 @@ module PuppetLitmus::Serverspec
35
37
  # @return [Object] A result object from the apply.
36
38
  def apply_manifest(manifest, opts = {})
37
39
  # rubocop:enable Layout/TrailingWhitespace
38
- target_node_name = ENV['TARGET_HOST']
40
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
39
41
  raise 'manifest and manifest_file_location in the opts hash are mutually exclusive arguments, pick one' if !manifest.nil? && !opts[:manifest_file_location].nil?
40
42
  raise 'please pass a manifest or the manifest_file_location in the opts hash' if (manifest.nil? || manifest == '') && opts[:manifest_file_location].nil?
43
+ raise 'please specify only one of `catch_changes`, `expect_changes`, `catch_failures` or `expect_failures`' if
44
+ [opts[:catch_changes], opts[:expect_changes], opts[:catch_failures], opts[:expect_failures]].compact.length > 1
45
+
46
+ if opts[:catch_changes]
47
+ use_detailed_exit_codes = true
48
+ acceptable_exit_codes = [0]
49
+ elsif opts[:catch_failures]
50
+ use_detailed_exit_codes = true
51
+ acceptable_exit_codes = [0, 2]
52
+ elsif opts[:expect_failures]
53
+ use_detailed_exit_codes = true
54
+ acceptable_exit_codes = [1, 4, 6]
55
+ elsif opts[:expect_changes]
56
+ use_detailed_exit_codes = true
57
+ acceptable_exit_codes = [2]
58
+ else
59
+ use_detailed_exit_codes = false
60
+ acceptable_exit_codes = [0]
61
+ end
41
62
 
42
63
  manifest_file_location = opts[:manifest_file_location] || create_manifest_file(manifest)
43
- inventory_hash = if target_node_name.nil? || target_node_name == 'localhost'
44
- nil
45
- else
46
- inventory_hash_from_inventory_file
47
- end
64
+ inventory_hash = File.exist?('inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
65
+ raise "Target '#{target_node_name}' not found in inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
66
+
48
67
  command_to_run = "#{opts[:prefix_command]} puppet apply #{manifest_file_location}"
49
- command_to_run += " --modulepath #{Dir.pwd}/spec/fixtures/modules" if target_node_name.nil? || target_node_name == 'localhost'
68
+ command_to_run += " --modulepath #{Dir.pwd}/spec/fixtures/modules" if target_node_name == 'litmus_localhost'
50
69
  command_to_run += " --hiera_config='#{opts[:hiera_config]}'" unless opts[:hiera_config].nil?
51
- command_to_run += ' --detailed-exitcodes' if !opts[:catch_changes].nil? && (opts[:catch_changes] == true)
52
70
  command_to_run += ' --debug' if !opts[:debug].nil? && (opts[:debug] == true)
53
71
  command_to_run += ' --noop' if !opts[:noop].nil? && (opts[:noop] == true)
54
- result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
72
+ command_to_run += ' --detailed-exitcodes' if use_detailed_exit_codes == true
55
73
 
56
- raise "apply manifest failed\n`#{command_to_run}`\n======\n#{result}" if result.first['result']['exit_code'] != 0 && opts[:expect_failures] != true
74
+ result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
75
+ status = result.first['result']['exit_code']
76
+ if opts[:catch_changes] && !acceptable_exit_codes.include?(status)
77
+ report_puppet_apply_change(command_to_run, result)
78
+ elsif !acceptable_exit_codes.include?(status)
79
+ report_puppet_apply_error(command_to_run, result, acceptable_exit_codes)
80
+ end
57
81
 
58
82
  result = OpenStruct.new(exit_code: result.first['result']['exit_code'],
59
83
  stdout: result.first['result']['stdout'],
@@ -98,12 +122,10 @@ module PuppetLitmus::Serverspec
98
122
  # @yieldreturn [Block] this method will yield to a block of code passed by the caller; this can be used for additional validation, etc.
99
123
  # @return [Object] A result object from the command.
100
124
  def run_shell(command_to_run, opts = {})
101
- target_node_name = ENV['TARGET_HOST']
102
- inventory_hash = if target_node_name.nil? || target_node_name == 'localhost'
103
- nil
104
- else
105
- inventory_hash_from_inventory_file
106
- end
125
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
126
+ inventory_hash = File.exist?('inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
127
+ raise "Target '#{target_node_name}' not found in inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
128
+
107
129
  result = run_command(command_to_run, target_node_name, config: nil, inventory: inventory_hash)
108
130
  raise "shell failed\n`#{command_to_run}`\n======\n#{result}" if result.first['result']['exit_code'] != 0 && opts[:expect_failures] != true
109
131
 
@@ -122,12 +144,9 @@ module PuppetLitmus::Serverspec
122
144
  # @yieldreturn [Block] this method will yield to a block of code passed by the caller; this can be used for additional validation, etc.
123
145
  # @return [Object] A result object from the command.
124
146
  def bolt_upload_file(source, destination, opts = {}, options = {})
125
- target_node_name = ENV['TARGET_HOST'] if target_node_name.nil?
126
- inventory_hash = if target_node_name.nil? || target_node_name == 'localhost'
127
- nil
128
- else
129
- inventory_hash_from_inventory_file
130
- end
147
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
148
+ inventory_hash = File.exist?('inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
149
+ raise "Target '#{target_node_name}' not found in inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
131
150
 
132
151
  result = upload_file(source, destination, target_node_name, options: options, config: nil, inventory: inventory_hash)
133
152
 
@@ -160,12 +179,9 @@ module PuppetLitmus::Serverspec
160
179
  # @return [Object] A result object from the task.The values available are stdout, stderr and result.
161
180
  def run_bolt_task(task_name, params = {}, opts = {})
162
181
  config_data = { 'modulepath' => File.join(Dir.pwd, 'spec', 'fixtures', 'modules') }
163
- target_node_name = ENV['TARGET_HOST'] if target_node_name.nil?
164
- inventory_hash = if target_node_name.nil? || target_node_name == 'localhost'
165
- nil
166
- else
167
- inventory_hash_from_inventory_file
168
- end
182
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
183
+ inventory_hash = File.exist?('inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
184
+ raise "Target '#{target_node_name}' not found in inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
169
185
 
170
186
  result = run_task(task_name, target_node_name, params, config: config_data, inventory: inventory_hash)
171
187
  result_obj = {
@@ -210,12 +226,9 @@ module PuppetLitmus::Serverspec
210
226
  # @yieldreturn [Block] this method will yield to a block of code passed by the caller; this can be used for additional validation, etc.
211
227
  # @return [Object] A result object from the script run.
212
228
  def bolt_run_script(script, opts = {}, arguments: [])
213
- target_node_name = ENV['TARGET_HOST'] if target_node_name.nil?
214
- inventory_hash = if target_node_name.nil? || target_node_name == 'localhost'
215
- nil
216
- else
217
- inventory_hash_from_inventory_file
218
- end
229
+ target_node_name = targeting_localhost? ? 'litmus_localhost' : ENV['TARGET_HOST']
230
+ inventory_hash = File.exist?('inventory.yaml') ? inventory_hash_from_inventory_file : localhost_inventory_hash
231
+ raise "Target '#{target_node_name}' not found in inventory.yaml" unless target_in_inventory?(inventory_hash, target_node_name)
219
232
 
220
233
  result = run_script(script, target_node_name, arguments, options: opts, config: nil, inventory: inventory_hash)
221
234
 
@@ -227,4 +240,67 @@ module PuppetLitmus::Serverspec
227
240
  yield result if block_given?
228
241
  result
229
242
  end
243
+
244
+ # Determines if the current execution is targeting localhost or not
245
+ #
246
+ # @return [Boolean] true if targeting localhost in the tests
247
+ def targeting_localhost?
248
+ ENV['TARGET_HOST'].nil? || ENV['TARGET_HOST'] == 'localhost'
249
+ end
250
+
251
+ private
252
+
253
+ # Report an error in the puppet run
254
+ #
255
+ # @param command [String] The puppet command causing the error.
256
+ # @param result [Array] The result struct containing the result
257
+ def report_puppet_apply_error(command, result, acceptable_exit_codes)
258
+ puppet_apply_error = <<-ERROR
259
+ apply manifest failed
260
+ `#{command}`
261
+ with exit code #{result.first['result']['exit_code']} (expected: #{acceptable_exit_codes})
262
+ ====== Start output of failed Puppet apply ======
263
+ #{puppet_output(result)}
264
+ ====== End output of failed Puppet apply ======
265
+ ERROR
266
+ raise puppet_apply_error
267
+ end
268
+
269
+ # Report an unexpected change in the puppet run
270
+ #
271
+ # @param command [String] The puppet command causing the error.
272
+ # @param result [Array] The result struct containing the result
273
+ def report_puppet_apply_change(command, result)
274
+ puppet_apply_changes = <<-ERROR
275
+ apply manifest expected no changes
276
+ `#{command}`
277
+ ====== Start output of Puppet apply with unexpected changes ======
278
+ #{puppet_output(result)}
279
+ ====== End output of Puppet apply with unexpected changes ======
280
+ ERROR
281
+ raise puppet_apply_changes
282
+ end
283
+
284
+ # Return the stdout of the puppet run
285
+ def puppet_output(result)
286
+ result.dig(0, 'result', 'stderr').to_s << \
287
+ result.dig(0, 'result', 'stdout').to_s
288
+ end
289
+
290
+ # Checks a puppet return status and returns true if it both
291
+ # the catalog compiled and the apply was successful. Either
292
+ # with or without changes
293
+ #
294
+ # @param exit_status [Integer] The status of the puppet run.
295
+ def puppet_successful?(exit_status)
296
+ [0, 2].include?(exit_status)
297
+ end
298
+
299
+ # Checks a puppet return status and returns true if
300
+ # puppet reported any changes
301
+ #
302
+ # @param exit_status [Integer] The status of the puppet run.
303
+ def puppet_changes?(exit_status)
304
+ [2, 6].include?(exit_status)
305
+ end
230
306
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # version of this gem
4
4
  module PuppetLitmus
5
- VERSION ||= '0.9.1'
5
+ VERSION ||= '0.10.0'
6
6
  end
@@ -25,7 +25,8 @@ RSpec.describe PuppetLitmus::InventoryManipulation do
25
25
  'nodes' =>
26
26
  [{ 'name' => 'test.delivery.puppetlabs.net',
27
27
  'config' => { 'transport' => 'ssh', 'ssh' => { 'user' => 'root', 'password' => 'Qu@lity!', 'host-key-check' => false } },
28
- 'facts' => { 'provisioner' => 'vmpooler', 'platform' => 'centos-5-x86_64' } }] },
28
+ 'facts' => { 'provisioner' => 'vmpooler', 'platform' => 'centos-5-x86_64' },
29
+ 'vars' => { 'role' => 'agent' } }] },
29
30
  { 'name' => 'winrm_nodes', 'nodes' => [] }] }
30
31
  end
31
32
 
@@ -98,6 +99,14 @@ RSpec.describe PuppetLitmus::InventoryManipulation do
98
99
  { 'user' => 'root', 'password' => 'Qu@lity!', 'host-key-check' => false })
99
100
  end
100
101
 
102
+ it 'facts exists, and returns' do
103
+ expect(dummy_class.facts_from_node(config_hash, 'test.delivery.puppetlabs.net')).to eq('provisioner' => 'vmpooler', 'platform' => 'centos-5-x86_64')
104
+ end
105
+
106
+ it 'vars exists, and returns' do
107
+ expect(dummy_class.vars_from_node(config_hash, 'test.delivery.puppetlabs.net')).to eq('role' => 'agent')
108
+ end
109
+
101
110
  it 'no feature exists for the group, and returns hash with feature added' do
102
111
  expect(dummy_class.add_feature_to_group(no_feature_hash, 'puppet-agent', 'ssh_nodes')).to eq('groups' => [{ 'features' => ['puppet-agent'], 'name' => 'ssh_nodes', 'nodes' => [{ 'config' => { 'ssh' => { 'host-key-check' => false, 'password' => 'Qu@lity!', 'user' => 'root' }, 'transport' => 'ssh' }, 'facts' => { 'platform' => 'centos-5-x86_64', 'provisioner' => 'vmpooler' }, 'name' => 'test.delivery.puppetlabs.net' }] }, { 'name' => 'winrm_nodes', 'nodes' => [] }]) # rubocop:disable Metrics/LineLength: Line is too long
103
112
  end
@@ -16,7 +16,7 @@ RSpec.describe PuppetLitmus::Serverspec do
16
16
 
17
17
  it 'calls all functions' do
18
18
  expect(dummy_class).to receive(:create_manifest_file).with(manifest).and_return('/bla.pp')
19
- expect(dummy_class).to receive(:apply_manifest).with(nil, catch_failures: true, manifest_file_location: '/bla.pp')
19
+ expect(dummy_class).to receive(:apply_manifest).with(nil, expect_failures: false, manifest_file_location: '/bla.pp')
20
20
  expect(dummy_class).to receive(:apply_manifest).with(nil, catch_changes: true, manifest_file_location: '/bla.pp')
21
21
  dummy_class.idempotent_apply(manifest)
22
22
  end
@@ -25,21 +25,74 @@ RSpec.describe PuppetLitmus::Serverspec do
25
25
  describe '.apply_manifest' do
26
26
  context 'when specifying a hiera config' do
27
27
  let(:manifest) { "include '::doot'" }
28
+ let(:localhost_inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'litmus_localhost', 'config' => { 'transport' => 'local' } }] }] } }
28
29
  let(:result) { ['result' => { 'exit_code' => 0, 'stdout' => nil, 'stderr' => nil }] }
29
30
  let(:command) { " puppet apply /bla.pp --modulepath #{Dir.pwd}/spec/fixtures/modules --hiera_config='/hiera.yaml'" }
30
31
 
31
32
  it 'passes the --hiera_config flag if the :hiera_config opt is specified' do
33
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
34
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
35
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
32
36
  expect(dummy_class).to receive(:create_manifest_file).with(manifest).and_return('/bla.pp')
33
- expect(dummy_class).to receive(:run_command).with(command, nil, config: nil, inventory: nil).and_return(result)
37
+ expect(dummy_class).to receive(:run_command).with(command, 'litmus_localhost', config: nil, inventory: localhost_inventory_hash).and_return(result)
34
38
  dummy_class.apply_manifest(manifest, hiera_config: '/hiera.yaml')
35
39
  end
36
40
  end
41
+
42
+ context 'when using detailed-exitcodes' do
43
+ let(:manifest) { "include '::doot'" }
44
+ let(:localhost_inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'litmus_localhost', 'config' => { 'transport' => 'local' } }] }] } }
45
+ let(:result) { ['result' => { 'exit_code' => 0, 'stdout' => nil, 'stderr' => nil }] }
46
+ let(:command) { " puppet apply /bla.pp --modulepath #{Dir.pwd}/spec/fixtures/modules --detailed-exitcodes" }
47
+
48
+ it 'uses detailed-exitcodes with expect_failures' do
49
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
50
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
51
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
52
+ expect(dummy_class).to receive(:create_manifest_file).with(manifest).and_return('/bla.pp')
53
+ expect(dummy_class).to receive(:run_command).with(command, 'litmus_localhost', config: nil, inventory: localhost_inventory_hash).and_return(result)
54
+ expect { dummy_class.apply_manifest(manifest, expect_failures: true) }.to raise_error(RuntimeError)
55
+ end
56
+
57
+ it 'uses detailed-exitcodes with catch_failures' do
58
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
59
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
60
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
61
+ expect(dummy_class).to receive(:create_manifest_file).with(manifest).and_return('/bla.pp')
62
+ expect(dummy_class).to receive(:run_command).with(command, 'litmus_localhost', config: nil, inventory: localhost_inventory_hash).and_return(result)
63
+ dummy_class.apply_manifest(manifest, catch_failures: true)
64
+ end
65
+
66
+ it 'uses detailed-exitcodes with expect_changes' do
67
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
68
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
69
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
70
+ expect(dummy_class).to receive(:create_manifest_file).with(manifest).and_return('/bla.pp')
71
+ expect(dummy_class).to receive(:run_command).with(command, 'litmus_localhost', config: nil, inventory: localhost_inventory_hash).and_return(result)
72
+ expect { dummy_class.apply_manifest(manifest, expect_changes: true) }.to raise_error(RuntimeError)
73
+ end
74
+
75
+ it 'uses detailed-exitcodes with catch_changes' do
76
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
77
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
78
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
79
+ expect(dummy_class).to receive(:create_manifest_file).with(manifest).and_return('/bla.pp')
80
+ expect(dummy_class).to receive(:run_command).with(command, 'litmus_localhost', config: nil, inventory: localhost_inventory_hash).and_return(result)
81
+ dummy_class.apply_manifest(manifest, catch_changes: true)
82
+ end
83
+
84
+ it 'uses raises exception for multiple options' do
85
+ expect { dummy_class.apply_manifest(manifest, catch_changes: true, expect_failures: true) }
86
+ .to raise_error(RuntimeError, 'please specify only one of `catch_changes`, `expect_changes`, `catch_failures` or `expect_failures`')
87
+ end
88
+ end
37
89
  end
38
90
 
39
91
  describe '.run_shell' do
40
92
  let(:command_to_run) { "puts 'doot'" }
41
93
  let(:result) { ['result' => { 'exit_code' => 0, 'stdout' => nil, 'stderr' => nil }] }
42
- let(:inventory_hash) { Hash.new(0) }
94
+ let(:inventory_hash) { { 'groups' => [{ 'name' => 'ssh_nodes', 'nodes' => [{ 'name' => 'some.host' }] }] } }
95
+ let(:localhost_inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'litmus_localhost', 'config' => { 'transport' => 'local' } }] }] } }
43
96
 
44
97
  it 'responds to run_shell' do
45
98
  expect(dummy_class).to respond_to(:run_shell).with(1..2).arguments
@@ -48,7 +101,10 @@ RSpec.describe PuppetLitmus::Serverspec do
48
101
  context 'when running against localhost and no inventory.yaml file' do
49
102
  it 'does run_shell against localhost without error' do
50
103
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'localhost'))
51
- expect(dummy_class).to receive(:run_command).with(command_to_run, 'localhost', config: nil, inventory: nil).and_return(result)
104
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
105
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
106
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
107
+ expect(dummy_class).to receive(:run_command).with(command_to_run, 'litmus_localhost', config: nil, inventory: localhost_inventory_hash).and_return(result)
52
108
  expect { dummy_class.run_shell(command_to_run) }.not_to raise_error
53
109
  end
54
110
  end
@@ -56,7 +112,9 @@ RSpec.describe PuppetLitmus::Serverspec do
56
112
  context 'when running against remote host' do
57
113
  it 'does run_shell against remote host without error' do
58
114
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
115
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
59
116
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
117
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
60
118
  expect(dummy_class).to receive(:run_command).with(command_to_run, 'some.host', config: nil, inventory: inventory_hash).and_return(result)
61
119
  expect { dummy_class.run_shell(command_to_run) }.not_to raise_error
62
120
  end
@@ -71,7 +129,8 @@ RSpec.describe PuppetLitmus::Serverspec do
71
129
  let(:result_success) {[{'node'=>'some.host','target'=>'some.host','action'=>'upload','object'=>'C:\foo\bar.ps1','status'=>'success','result'=>{'_output'=>'Uploaded \'C:\foo\bar.ps1\' to \'some.host:C:\bar\''}}]}
72
130
  let(:result_failure) {[{'node'=>'some.host','target'=>'some.host','action'=>nil,'object'=>nil,'status'=>'failure','result'=>{'_error'=>{'kind'=>'puppetlabs.tasks/task_file_error','msg'=>'No such file or directory @ rb_sysopen - /nonexistant/file/path','details'=>{},'issue_code'=>'WRITE_ERROR'}}}]}
73
131
  # rubocop:enable SpaceInsideHashLiteralBraces, SpaceInsideBlockBraces, SpaceAroundOperators, LineLength, SpaceAfterComma
74
- let(:inventory_hash) { Hash.new(0) }
132
+ let(:inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'some.host', 'config' => { 'transport' => 'local' } }] }] } }
133
+ let(:localhost_inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'litmus_localhost', 'config' => { 'transport' => 'local' } }] }] } }
75
134
 
76
135
  it 'responds to run_shell' do
77
136
  expect(dummy_class).to respond_to(:bolt_upload_file).with(2..3).arguments
@@ -80,14 +139,19 @@ RSpec.describe PuppetLitmus::Serverspec do
80
139
  context 'when upload returns success' do
81
140
  it 'does upload_file against remote host without error' do
82
141
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
142
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
83
143
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
144
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
84
145
  expect(dummy_class).to receive(:upload_file).with(local, remote, 'some.host', options: {}, config: nil, inventory: inventory_hash).and_return(result_success)
85
146
  expect { dummy_class.bolt_upload_file(local, remote) }.not_to raise_error
86
147
  end
87
148
  it 'does upload_file against localhost without error' do
88
149
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'localhost'))
150
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
151
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
89
152
  expect(dummy_class).not_to receive(:inventory_hash_from_inventory_file)
90
- expect(dummy_class).to receive(:upload_file).with(local, remote, 'localhost', options: {}, config: nil, inventory: nil).and_return(result_success)
153
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
154
+ expect(dummy_class).to receive(:upload_file).with(local, remote, 'litmus_localhost', options: {}, config: nil, inventory: localhost_inventory_hash).and_return(result_success)
91
155
  expect { dummy_class.bolt_upload_file(local, remote) }.not_to raise_error
92
156
  end
93
157
  end
@@ -95,13 +159,17 @@ RSpec.describe PuppetLitmus::Serverspec do
95
159
  context 'when upload returns failure' do
96
160
  it 'does upload_file gives runtime error for failure' do
97
161
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
162
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
98
163
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
164
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
99
165
  expect(dummy_class).to receive(:upload_file).with(local, remote, 'some.host', options: {}, config: nil, inventory: inventory_hash).and_return(result_failure)
100
166
  expect { dummy_class.bolt_upload_file(local, remote) }.to raise_error(RuntimeError, %r{upload file failed})
101
167
  end
102
168
  it 'returns the exit code and error message when expecting failure' do
103
169
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
170
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
104
171
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
172
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
105
173
  expect(dummy_class).to receive(:upload_file).with(local, remote, 'some.host', options: {}, config: nil, inventory: inventory_hash).and_return(result_failure)
106
174
  method_result = dummy_class.bolt_upload_file(local, remote, expect_failures: true)
107
175
  expect(method_result.exit_code).to be(255)
@@ -113,7 +181,8 @@ RSpec.describe PuppetLitmus::Serverspec do
113
181
  describe '.bolt_run_script' do
114
182
  let(:script) { '/tmp/script.sh' }
115
183
  let(:result) { ['result' => { 'exit_code' => 0, 'stdout' => nil, 'stderr' => nil }] }
116
- let(:inventory_hash) { Hash.new(0) }
184
+ let(:inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'some.host', 'config' => { 'transport' => 'local' } }] }] } }
185
+ let(:localhost_inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'litmus_localhost', 'config' => { 'transport' => 'local' } }] }] } }
117
186
 
118
187
  it 'responds to bolt_run_script' do
119
188
  expect(dummy_class).to respond_to(:bolt_run_script).with(1..2).arguments
@@ -122,8 +191,11 @@ RSpec.describe PuppetLitmus::Serverspec do
122
191
  context 'when running against localhost and no inventory.yaml file' do
123
192
  it 'does bolt_run_script against localhost without error' do
124
193
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'localhost'))
194
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
195
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
125
196
  expect(dummy_class).not_to receive(:inventory_hash_from_inventory_file)
126
- expect(dummy_class).to receive(:run_script).with(script, 'localhost', [], options: {}, config: nil, inventory: nil).and_return(result)
197
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
198
+ expect(dummy_class).to receive(:run_script).with(script, 'litmus_localhost', [], options: {}, config: nil, inventory: localhost_inventory_hash).and_return(result)
127
199
  expect { dummy_class.bolt_run_script(script) }.not_to raise_error
128
200
  end
129
201
  end
@@ -131,7 +203,9 @@ RSpec.describe PuppetLitmus::Serverspec do
131
203
  context 'when running against remote host' do
132
204
  it 'does bolt_run_script against remote host without error' do
133
205
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
206
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
134
207
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file)
208
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
135
209
  expect(dummy_class).to receive(:run_script).with(script, 'some.host', [], options: {}, config: nil, inventory: nil).and_return(result)
136
210
  expect { dummy_class.bolt_run_script(script) }.not_to raise_error
137
211
  end
@@ -140,8 +214,11 @@ RSpec.describe PuppetLitmus::Serverspec do
140
214
  context 'when running with arguments' do
141
215
  it 'does bolt_run_script with arguments without error' do
142
216
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'localhost'))
217
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(false)
218
+ expect(dummy_class).to receive(:localhost_inventory_hash).and_return(localhost_inventory_hash)
143
219
  expect(dummy_class).not_to receive(:inventory_hash_from_inventory_file)
144
- expect(dummy_class).to receive(:run_script).with(script, 'localhost', ['doot'], options: {}, config: nil, inventory: nil).and_return(result)
220
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
221
+ expect(dummy_class).to receive(:run_script).with(script, 'litmus_localhost', ['doot'], options: {}, config: nil, inventory: localhost_inventory_hash).and_return(result)
145
222
  expect { dummy_class.bolt_run_script(script, arguments: ['doot']) }.not_to raise_error
146
223
  end
147
224
  end
@@ -157,7 +234,7 @@ RSpec.describe PuppetLitmus::Serverspec do
157
234
  let(:result_structured_task_success){ [{'node'=>'some.host','target'=>'some.host','action'=>'task','object'=>'testtask::structured','status'=>'success','result'=>{'key1'=>'foo','key2'=>'bar'}}]}
158
235
  let(:result_failure) {[{'node'=>'some.host','target'=>'some.host','action'=>'task','object'=>'testtask::unstructured','status'=>'failure','result'=>{'_error'=>{'msg'=>'FAILURE!','kind'=>'puppetlabs.tasks/task-error','details'=>{'exitcode'=>123}}}}]}
159
236
  # rubocop:enable SpaceInsideHashLiteralBraces, SpaceBeforeBlockBraces, SpaceInsideBlockBraces, SpaceAroundOperators, LineLength, SpaceAfterComma
160
- let(:inventory_hash) { Hash.new(0) }
237
+ let(:inventory_hash) { { 'groups' => [{ 'name' => 'local', 'nodes' => [{ 'name' => 'some.host', 'config' => { 'transport' => 'local' } }] }] } }
161
238
 
162
239
  it 'responds to bolt_run_task' do
163
240
  expect(dummy_class).to respond_to(:run_bolt_task).with(2..3).arguments
@@ -166,20 +243,26 @@ RSpec.describe PuppetLitmus::Serverspec do
166
243
  context 'when bolt returns success' do
167
244
  it 'does bolt_task_run gives no runtime error for success' do
168
245
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
246
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
169
247
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
248
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
170
249
  expect(dummy_class).to receive(:run_task).with(task_name, 'some.host', params, config: config_data, inventory: inventory_hash).and_return(result_unstructured_task_success)
171
250
  expect { dummy_class.run_bolt_task(task_name, params, opts: {}) }.not_to raise_error
172
251
  end
173
252
  it 'returns stdout for unstructured-data tasks' do
174
253
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
254
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
175
255
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
256
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
176
257
  expect(dummy_class).to receive(:run_task).with(task_name, 'some.host', params, config: config_data, inventory: inventory_hash).and_return(result_unstructured_task_success)
177
258
  method_result = dummy_class.run_bolt_task(task_name, params, opts: {})
178
259
  expect(method_result.stdout).to eq('SUCCESS!')
179
260
  end
180
261
  it 'returns structured output for structured-data tasks' do
181
262
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
263
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
182
264
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
265
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
183
266
  expect(dummy_class).to receive(:run_task).with(task_name, 'some.host', params, config: config_data, inventory: inventory_hash).and_return(result_structured_task_success)
184
267
  method_result = dummy_class.run_bolt_task(task_name, params, opts: {})
185
268
  expect(method_result.stdout).to eq('{"key1"=>"foo", "key2"=>"bar"}')
@@ -191,13 +274,17 @@ RSpec.describe PuppetLitmus::Serverspec do
191
274
  context 'when bolt returns failure' do
192
275
  it 'does bolt_task_run gives runtime error for failure' do
193
276
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
277
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
194
278
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
279
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
195
280
  expect(dummy_class).to receive(:run_task).with(task_name, 'some.host', params, config: config_data, inventory: inventory_hash).and_return(result_failure)
196
281
  expect { dummy_class.run_bolt_task(task_name, params, opts: {}) }.to raise_error(RuntimeError, %r{task failed})
197
282
  end
198
283
  it 'returns the exit code and error message when expecting failure' do
199
284
  stub_const('ENV', ENV.to_hash.merge('TARGET_HOST' => 'some.host'))
285
+ expect(File).to receive(:exist?).with('inventory.yaml').and_return(true)
200
286
  expect(dummy_class).to receive(:inventory_hash_from_inventory_file).and_return(inventory_hash)
287
+ expect(dummy_class).to receive(:target_in_inventory?).and_return(true)
201
288
  expect(dummy_class).to receive(:run_task).with(task_name, 'some.host', params, config: config_data, inventory: inventory_hash).and_return(result_failure)
202
289
  method_result = dummy_class.run_bolt_task(task_name, params, expect_failures: true)
203
290
  expect(method_result.exit_code).to be(123)
data/spec/spec_helper.rb CHANGED
@@ -6,9 +6,14 @@ require 'puppet_litmus'
6
6
  if ENV['COVERAGE'] == 'yes'
7
7
  require 'simplecov'
8
8
 
9
- SimpleCov.formatters = [
10
- SimpleCov::Formatter::HTMLFormatter,
11
- ]
9
+ if ENV['CI'] == 'true'
10
+ require 'codecov'
11
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
12
+ else
13
+ SimpleCov.formatters = [
14
+ SimpleCov::Formatter::HTMLFormatter,
15
+ ]
16
+ end
12
17
  SimpleCov.start do
13
18
  track_files 'lib/**/*.rb'
14
19
 
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.9.1
4
+ version: 0.10.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-08-30 00:00:00.000000000 Z
11
+ date: 2019-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bolt
@@ -111,15 +111,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
111
  version: '0'
112
112
  requirements: []
113
113
  rubyforge_project:
114
- rubygems_version: 2.7.6
114
+ rubygems_version: 2.7.10
115
115
  signing_key:
116
116
  specification_version: 4
117
117
  summary: Providing a simple command line tool for puppet content creators, to enable
118
118
  simple and complex test deployments.
119
119
  test_files:
120
- - spec/data/inventory.yaml
121
- - spec/lib/puppet_litmus/serverspec_spec.rb
122
- - spec/lib/puppet_litmus/inventory_manipulation_spec.rb
120
+ - spec/spec_helper.rb
123
121
  - spec/lib/puppet_litmus/rake_tasks_spec.rb
124
122
  - spec/lib/puppet_litmus/version_spec.rb
125
- - spec/spec_helper.rb
123
+ - spec/lib/puppet_litmus/inventory_manipulation_spec.rb
124
+ - spec/lib/puppet_litmus/serverspec_spec.rb
125
+ - spec/data/inventory.yaml