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 +4 -4
- data/lib/puppet_litmus/inventory_manipulation.rb +44 -0
- data/lib/puppet_litmus/rake_tasks.rb +41 -100
- data/lib/puppet_litmus/serverspec.rb +113 -37
- data/lib/puppet_litmus/version.rb +1 -1
- data/spec/lib/puppet_litmus/inventory_manipulation_spec.rb +10 -1
- data/spec/lib/puppet_litmus/serverspec_spec.rb +97 -10
- data/spec/spec_helper.rb +8 -3
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b4b8f9d03595ac86920511bc3ec0429c34e99ebb54fce2e0dd80bce3d233145
|
4
|
+
data.tar.gz: c4a3bd340f4e215faa647111b6ba933d5669a43e4c06474ab4bc41766fb36235
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
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
|
-
|
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
|
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,
|
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]
|
28
|
-
# :
|
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 =
|
44
|
-
|
45
|
-
|
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
|
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
|
-
|
72
|
+
command_to_run += ' --detailed-exitcodes' if use_detailed_exit_codes == true
|
55
73
|
|
56
|
-
|
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 =
|
103
|
-
|
104
|
-
|
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']
|
126
|
-
inventory_hash =
|
127
|
-
|
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']
|
164
|
-
inventory_hash =
|
165
|
-
|
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']
|
214
|
-
inventory_hash =
|
215
|
-
|
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
|
@@ -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,
|
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,
|
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) {
|
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(
|
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) {
|
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(:
|
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) {
|
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(:
|
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(:
|
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) {
|
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
|
-
|
10
|
-
|
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.
|
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-
|
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.
|
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/
|
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/
|
123
|
+
- spec/lib/puppet_litmus/inventory_manipulation_spec.rb
|
124
|
+
- spec/lib/puppet_litmus/serverspec_spec.rb
|
125
|
+
- spec/data/inventory.yaml
|