Skip to content

Commit 2805aa6

Browse files
author
Wilson McCoubrey
committed
[PE-17491] Do not fail on install when a restart exit code is returned
When exit code 3010 is returned from setup.exe upon install the puppet run failed even though the install succeeded, the 3010 exit code just signifies that some changes are pending and a restart is required. This change allows the puppet run to succeed when the install returns 3010 exit code and simply raises a warning.
1 parent e8721c6 commit 2805aa6

File tree

6 files changed

+116
-26
lines changed

6 files changed

+116
-26
lines changed

lib/puppet/provider/sqlserver.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ class Puppet::Provider::Sqlserver < Puppet::Provider
1717
'powershell.exe'
1818
end
1919

20-
def try_execute(command, msg = nil, obfuscate_strings = nil)
21-
begin
22-
execute(command.compact)
23-
rescue Puppet::ExecutionFailure => error
20+
def try_execute(command, msg = nil, obfuscate_strings = nil, acceptable_exit_codes = [0])
21+
res = execute(command.compact, failonfail: false)
22+
23+
unless acceptable_exit_codes.include?(res.exitstatus)
2424
msg = "Failure occured when trying to install SQL Server #{@resource[:name]}" if msg.nil?
25-
msg += " \n #{error}"
25+
msg += " \n Execution of '#{command}' returned #{res.exitstatus}: #{res.strip}"
2626

2727
obfuscate_strings.each {|str| msg.gsub!(str, '**HIDDEN VALUE**') } unless obfuscate_strings.nil?
2828

2929
raise Puppet::Error, msg
3030
end
31+
32+
res
3133
end
3234

3335
private

lib/puppet/provider/sqlserver_features/mssql.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ def modify_features(action, features)
6464
begin
6565
config_file = create_temp_for_install_switch unless action == 'uninstall'
6666
cmd_args << "/ConfigurationFile=\"#{config_file.path}\"" unless config_file.nil?
67-
try_execute(cmd_args, "Unable to #{action} features (#{features.join(', ')})")
67+
res = try_execute(cmd_args, "Unable to #{action} features (#{features.join(', ')})", nil, [0, 1641, 3010])
68+
69+
warn("#{action} of features (#{features.join(', ')} returned exit code 3010 - reboot required") if res.exitstatus == 3010
70+
warn("#{action} of features (#{features.join(', ')} returned exit code 1641 - reboot initiated") if res.exitstatus == 1641
6871
ensure
6972
if config_file
7073
config_file.close

lib/puppet/provider/sqlserver_instance/mssql.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ def modify_features(features, action)
4848
begin
4949
config_file = create_temp_for_install_switch unless action == 'uninstall'
5050
cmd_args << "/ConfigurationFile=\"#{config_file.path}\"" unless config_file.nil?
51-
try_execute(cmd_args, "Error trying to #{action} features (#{features.join(', ')}", obfuscated_strings)
51+
res = try_execute(cmd_args, "Error trying to #{action} features (#{features.join(', ')}", obfuscated_strings, [0, 1641, 3010])
52+
53+
warn("#{action} of features (#{features.join(', ')}) returned exit code 3010 - reboot required") if res.exitstatus == 3010
54+
warn("#{action} of features (#{features.join(', ')}) returned exit code 1641 - reboot initiated") if res.exitstatus == 1641
5255
ensure
5356
if config_file
5457
config_file.close
@@ -161,7 +164,11 @@ def format_cmd_args_array(switch, arr, cmd_args, use_discrete = false)
161164

162165
def destroy
163166
cmd_args = basic_cmd_args(current_installed_features, 'uninstall')
164-
try_execute(cmd_args, "Unable to uninstall instance #{@resource[:name]}")
167+
res = try_execute(cmd_args, "Unable to uninstall instance #{@resource[:name]}", nil, [0, 1641, 3010])
168+
169+
warn("Uninstall of instance #{@resource[:name]} returned exit code 3010 - reboot required") if res.exitstatus == 3010
170+
warn("Uninstall of instance #{@resource[:name]} returned exit code 1641 - reboot initiated") if res.exitstatus == 1641
171+
165172
@property_hash.clear
166173
exists? ? (return false) : (return true)
167174
end

spec/unit/puppet/provider/sqlserver__instance_spec.rb

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010
subject { provider_class }
1111
let(:additional_install_switches) { [] }
1212

13-
def stub_uninstall(args, installed_features)
13+
def stub_uninstall(args, installed_features, exit_code = 0)
1414
cmd_args = ["#{args[:source]}/setup.exe",
1515
"/ACTION=uninstall",
1616
'/Q',
1717
'/IACCEPTSQLSERVERLICENSETERMS',
1818
"/INSTANCENAME=#{args[:name]}",
1919
"/FEATURES=#{installed_features.join(',')}",]
20-
Puppet::Util::Execution.stubs(:execute).with(cmd_args.compact).returns(0)
20+
21+
result = Puppet::Util::Execution::ProcessOutput.new('', exit_code)
22+
Puppet::Util::Execution.stubs(:execute).with(cmd_args.compact, failonfail: false).returns(result)
2123
end
2224

2325
shared_examples 'run' do |args, munged_values = {}|
@@ -46,7 +48,7 @@ def stub_uninstall(args, installed_features)
4648
@provider.create
4749
}
4850
end
49-
shared_examples 'create' do
51+
shared_examples 'create' do |exit_code, warning_matcher|
5052
it {
5153
execute_args = args.merge(munged_values)
5254
@resource = Puppet::Type::Sqlserver_instance.new(args)
@@ -77,20 +79,27 @@ def stub_uninstall(args, installed_features)
7779
additional_install_switches.each do |switch|
7880
cmd_args << switch
7981
end
80-
Puppet::Util::Execution.stubs(:execute).with(cmd_args.compact).returns(0)
82+
83+
# If warning_matcher supplied ensure warnings raised match, otherwise no warnings raised
84+
@provider.stubs(:warn).with(regexp_matches(warning_matcher)).returns(nil).times(1) if warning_matcher
85+
@provider.stubs(:warn).with(anything).times(0) unless warning_matcher
86+
87+
result = Puppet::Util::Execution::ProcessOutput.new('', exit_code || 0)
88+
Puppet::Util::Execution.stubs(:execute).with(cmd_args.compact, failonfail: false).returns(result)
8189
@provider.create
8290
}
8391
end
8492

8593

86-
shared_examples 'destroy' do
94+
shared_examples 'destroy' do |exit_code, warning_matcher|
8795
it {
8896
@resource = Puppet::Type::Sqlserver_instance.new(args)
8997
@provider = provider_class.new(@resource)
9098

9199
stub_source_which_call args[:source]
92100
@provider.expects(:current_installed_features).returns(installed_features)
93-
stub_uninstall args, installed_features
101+
stub_uninstall args, installed_features, exit_code || 0
102+
@provider.stubs(:warn).with(regexp_matches(warning_matcher)).returns(nil).times(1) if warning_matcher
94103
@provider.destroy
95104
}
96105
end
@@ -118,6 +127,30 @@ def stub_uninstall(args, installed_features)
118127
end
119128
end
120129

130+
describe 'it should raise warning on install when 1641 exit code returned' do
131+
it_behaves_like 'create', 1641, /reboot initiated/i do
132+
args = get_basic_args
133+
let(:args) { args }
134+
munged = {:features => Array.new(args[:features])}
135+
munged[:features].delete('SQL')
136+
munged[:features] += %w(DQ FullText Replication SQLEngine)
137+
munged[:features].sort!
138+
let(:munged_values) { munged }
139+
end
140+
end
141+
142+
describe 'it should raise warning on install when 3010 exit code returned' do
143+
it_behaves_like 'create', 3010, /reboot required/i do
144+
args = get_basic_args
145+
let(:args) { args }
146+
munged = {:features => Array.new(args[:features])}
147+
munged[:features].delete('SQL')
148+
munged[:features] += %w(DQ FullText Replication SQLEngine)
149+
munged[:features].sort!
150+
let(:munged_values) { munged }
151+
end
152+
end
153+
121154
describe 'empty array should' do
122155
it_behaves_like 'destroy on create' do
123156
let(:installed_features) { %w(SQLEngine Replication) }
@@ -140,6 +173,29 @@ def stub_uninstall(args, installed_features)
140173
end
141174

142175
end
176+
177+
describe 'it should raise warning on uninstall when 1641 exit code returned' do
178+
it_behaves_like 'destroy', 1641, /reboot initiated/i do
179+
let(:args) { {
180+
:name => 'MYSQLSERVER',
181+
:source => 'C:\myinstallexecs',
182+
:features => []
183+
} }
184+
let(:installed_features) { %w(SQLEngine Replication) }
185+
end
186+
end
187+
188+
describe 'it should raise warning on uninstall when 3010 exit code returned' do
189+
it_behaves_like 'destroy', 3010, /reboot required/i do
190+
let(:args) { {
191+
:name => 'MYSQLSERVER',
192+
:source => 'C:\myinstallexecs',
193+
:features => []
194+
} }
195+
let(:installed_features) { %w(SQLEngine Replication) }
196+
end
197+
end
198+
143199
describe 'installed features even if provided features' do
144200
it_behaves_like 'destroy' do
145201
let(:args) { {

spec/unit/puppet/provider/sqlserver_features_spec.rb

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
let(:additional_params) { {} }
1616
let(:munged_args) { {} }
1717
let(:additional_switches) { [] }
18-
shared_examples 'create' do
18+
shared_examples 'create' do |exit_code, warning_matcher|
1919
it {
2020
params.merge!(additional_params)
2121
@resource = Puppet::Type::Sqlserver_features.new(params)
@@ -24,7 +24,8 @@
2424
stub_powershell_call(subject)
2525

2626
executed_args = params.merge(munged_args)
27-
stub_add_features(executed_args, executed_args[:features], additional_switches)
27+
stub_add_features(executed_args, executed_args[:features], additional_switches, exit_code || 0)
28+
@provider.stubs(:warn).with(regexp_matches(warning_matcher)).returns(nil).times(1) if warning_matcher
2829
@provider.create
2930
}
3031
end
@@ -65,20 +66,23 @@
6566
it_should_behave_like 'create'
6667
end
6768

68-
shared_examples 'features=' do |args|
69+
shared_examples 'features=' do |args, exit_code, warning_matcher|
6970
it {
7071
@resource = Puppet::Type::Sqlserver_features.new(args)
7172
@provider = provider_class.new(@resource)
7273

7374
stub_powershell_call(subject)
7475
stub_source_which_call args
7576
if !feature_remove.empty?
76-
stub_remove_features(args, feature_remove)
77+
stub_remove_features(args, feature_remove, exit_code || 0)
7778
end
7879
if !feature_add.empty?
79-
stub_add_features(args, feature_add)
80+
stub_add_features(args, feature_add, [], exit_code || 0)
8081
end
8182

83+
# If warning_matcher supplied ensure warnings raised match, otherwise no warnings raised
84+
@provider.stubs(:warn).with(regexp_matches(warning_matcher)).returns(nil).times(1) if warning_matcher
85+
@provider.stubs(:warn).with(anything).times(0) unless warning_matcher
8286
@provider.create
8387
}
8488
end
@@ -106,6 +110,20 @@
106110
it_should_behave_like 'features=', @feature_params
107111
end
108112

113+
context 'it should raise warning on feature install when 1641 exit code returned' do
114+
include_context 'features'
115+
@feature_params[:features] = %w(SSMS)
116+
let(:feature_add) { %w(SSMS) }
117+
it_should_behave_like 'features=', @feature_params, 1641, /reboot initiated/i
118+
end
119+
120+
context 'it should raise warning on feature install when 3010 exit code returned' do
121+
include_context 'features'
122+
@feature_params[:features] = %w(SSMS)
123+
let(:feature_add) { %w(SSMS) }
124+
it_should_behave_like 'features=', @feature_params, 3010, /reboot required/i
125+
end
126+
109127
context 'it should install the expanded tools set' do
110128
include_context 'features'
111129
@feature_params[:features] = %w(Tools)
@@ -131,13 +149,14 @@
131149
@provider = provider_class.new(@resource)
132150
@provider.stubs(:current_installed_features).returns(%w(SSMS ADV_SSMS Conn))
133151
Puppet::Util.stubs(:which).with("#{feature_params[:source]}/setup.exe").returns("#{feature_params[:source]}/setup.exe")
152+
result = Puppet::Util::Execution::ProcessOutput.new('', 0)
134153
Puppet::Util::Execution.expects(:execute).with(
135154
["#{feature_params[:source]}/setup.exe",
136155
"/ACTION=uninstall",
137156
'/Q',
138157
'/IACCEPTSQLSERVERLICENSETERMS',
139158
"/FEATURES=#{%w(SSMS ADV_SSMS Conn).join(',')}",
140-
]).returns(0)
159+
], failonfail: false).returns(result)
141160
@provider.create
142161
}
143162
end

spec/unit/puppet/sqlserver_spec_helper.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ def stub_powershell_call(subject)
77
Puppet::Provider::Sqlserver.stubs(:run_install_dot_net).returns()
88
end
99

10-
def stub_add_features(args, features, additional_switches = [])
11-
stub_modify_features('install', args, features, additional_switches)
10+
def stub_add_features(args, features, additional_switches = [], exit_code = 0)
11+
stub_modify_features('install', args, features, additional_switches, exit_code)
1212
end
1313

14-
def stub_remove_features(args, features)
15-
stub_modify_features('uninstall', args, features)
14+
def stub_remove_features(args, features, exit_code = 0)
15+
stub_modify_features('uninstall', args, features, [], exit_code)
1616
end
1717

18-
def stub_modify_features(action, args, features, additional_switches = [])
18+
def stub_modify_features(action, args, features, additional_switches = [], exit_code = 0)
1919
cmds = ["#{args[:source]}/setup.exe",
2020
"/ACTION=#{action}",
2121
'/Q',
@@ -31,5 +31,8 @@ def stub_modify_features(action, args, features, additional_switches = [])
3131
additional_switches.each do |switch|
3232
cmds << switch
3333
end
34-
Puppet::Util::Execution.stubs(:execute).with(cmds).returns(0)
34+
35+
result = Puppet::Util::Execution::ProcessOutput.new('', exit_code)
36+
37+
Puppet::Util::Execution.stubs(:execute).with(cmds, failonfail: false).returns(result)
3538
end

0 commit comments

Comments
 (0)