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