Skip to content

Commit 89d4f6d

Browse files
authored
Merge pull request #213 from puppetlabs/cat-1869-add_configurable_timeout
(CAT-1869) - Add configurable dsc_timeout param for dsc type
2 parents 7a589ab + fad6643 commit 89d4f6d

File tree

5 files changed

+62
-7
lines changed

5 files changed

+62
-7
lines changed

.rubocop_todo.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2024-05-28 13:36:04 UTC using RuboCop version 1.50.2.
3+
# on 2024-06-07 10:17:46 UTC using RuboCop version 1.50.2.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
77
# versions of RuboCop, may require this file to be generated again.
88

9-
# Offense count: 3
9+
# Offense count: 2
1010
# Configuration parameters: AllowedMethods.
1111
# AllowedMethods: enums
1212
Lint/ConstantDefinitionInBlock:
@@ -44,7 +44,7 @@ Metrics/AbcSize:
4444
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
4545
# AllowedMethods: refine
4646
Metrics/BlockLength:
47-
Max: 116
47+
Max: 134
4848

4949
# Offense count: 1
5050
# Configuration parameters: CountComments, CountAsOne.

REFERENCE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,17 @@ An optional property that specifies that the DSC resource should be invoked.
6767

6868
The following parameters are available in the `dsc` type.
6969

70+
* [`dsc_timeout`](#-dsc--dsc_timeout)
7071
* [`module`](#-dsc--module)
7172
* [`name`](#-dsc--name)
7273
* [`properties`](#-dsc--properties)
7374
* [`provider`](#-dsc--provider)
7475
* [`resource_name`](#-dsc--resource_name)
7576

77+
##### <a name="-dsc--dsc_timeout"></a>`dsc_timeout`
78+
79+
Specify a timeout for Invoke-DscResource.
80+
7681
##### <a name="-dsc--module"></a>`module`
7782

7883
Name of the DSC Resource module to use. For example, the xPSDesiredStateConfiguration DSC Resource module contains

lib/puppet/provider/base_dsc_lite/powershell.rb

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,25 +56,39 @@ def self.template_path
5656
File.expand_path(Pathname.new(__FILE__).dirname)
5757
end
5858

59+
def set_timeout
60+
resource[:dsc_timeout] ? resource[:dsc_timeout] * 1000 : 1_200_000
61+
end
62+
63+
def compile_timeout_msg(timeout)
64+
"The DSC Resource did not respond within the timeout limit of #{timeout} milliseconds. \
65+
This can occur if the DSC Resource is stuck in an infinite loop, or if the DSC Resource is waiting for user input. \
66+
Please check the DSC Resource for any prompts that may require user input, and ensure that the DSC Resource does not contain any infinite loops. \
67+
If the DSC Resource is functioning correctly, you may need to increase the timeout limit using the 'dsc_timeout' parameter"
68+
end
69+
5970
def ps_manager
6071
debug_output = Puppet::Util::Log.level == :debug
6172
Pwsh::Manager.instance(command(:powershell), Pwsh::Manager.powershell_args, debug: debug_output)
6273
end
6374

64-
DSC_LITE_COMMAND_TIMEOUT = 1_200_000 # 20 minutes
65-
6675
def exists?
76+
timeout = set_timeout
77+
Puppet.debug "Dsc Timeout: #{timeout} milliseconds"
6778
version = Facter.value(:powershell_version)
6879
Puppet.debug "PowerShell Version: #{version}"
6980
script_content = ps_script_content('test')
7081
Puppet.debug "\n" + self.class.redact_content(script_content)
7182

7283
if Pwsh::Manager.windows_powershell_supported?
73-
output = ps_manager.execute(script_content, DSC_LITE_COMMAND_TIMEOUT)[:stdout]
84+
output = ps_manager.execute(script_content, timeout)[:stdout]
7485
else
7586
self.class.upgrade_message
7687
output = powershell(Pwsh::Manager.powershell_args, script_content)
7788
end
89+
90+
raise Puppet::Error, compile_timeout_msg(timeout) if output.nil?
91+
7892
Puppet.debug "Dsc Resource returned: #{output}"
7993
data = JSON.parse(output)
8094
raise(data['errormessage']) unless data['errormessage'].empty?
@@ -87,15 +101,20 @@ def exists?
87101
end
88102

89103
def create
104+
timeout = set_timeout
105+
Puppet.debug "Dsc Timeout: #{timeout} milliseconds"
90106
script_content = ps_script_content('set')
91107
Puppet.debug "\n" + self.class.redact_content(script_content)
92108

93109
if Pwsh::Manager.windows_powershell_supported?
94-
output = ps_manager.execute(script_content, DSC_LITE_COMMAND_TIMEOUT)[:stdout]
110+
output = ps_manager.execute(script_content, timeout)[:stdout]
95111
else
96112
self.class.upgrade_message
97113
output = powershell(Pwsh::Manager.powershell_args, script_content)
98114
end
115+
116+
raise Puppet::Error, compile_timeout_msg(timeout) if output.nil?
117+
99118
Puppet.debug "Create Dsc Resource returned: #{output}"
100119
data = JSON.parse(output)
101120

lib/puppet/type/dsc.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ def change_to_s(currentvalue, newvalue)
5858
end
5959
end
6060

61+
newparam(:dsc_timeout) do
62+
desc 'Specify a timeout for Invoke-DscResource.'
63+
validate do |value|
64+
raise "#{name} should be an Integer" unless value.is_a? Integer
65+
end
66+
end
67+
6168
newparam(:resource_name) do
6269
desc 'Name of the DSC Resource to use. For example, the xRemoteFile DSC Resource.'
6370
validate do |value|

spec/acceptance/dsc_type/psdesiredstateconfiguration_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ module => 'PSDesiredStateConfiguration',
3434
MANIFEST
3535
end
3636

37+
let(:dsc_timeout_manifest) do
38+
<<-MANIFEST
39+
dsc { "Running Script":
40+
resource_name => 'Script',
41+
module => 'PSDesiredStateConfiguration',
42+
dsc_timeout => 1,
43+
properties => {
44+
getscript => 'Start-Sleep -Seconds 2',
45+
testscript => '$false',
46+
setscript => 'Start-Sleep -Seconds 2',
47+
},
48+
}
49+
MANIFEST
50+
end
51+
3752
context 'create a standard DSC File' do
3853
it 'applies manifest' do
3954
apply_manifest(dsc_manifest, catch_failures: true) do |result|
@@ -46,6 +61,15 @@ module => 'PSDesiredStateConfiguration',
4661
end
4762
end
4863

64+
context 'times out when execution time is greater than dsc_timeout' do
65+
it 'applies manifest' do
66+
apply_manifest(dsc_timeout_manifest, expect_failures: true) do |result|
67+
expect(result.stderr).to match(%r{The DSC Resource did not respond within the timeout limit of 1000 milliseconds})
68+
end
69+
sleep(15) # Wait for the DSC Resource to finish execution
70+
end
71+
end
72+
4973
context 'remove a standard DSC File' do
5074
it 'applies manifest' do
5175
apply_manifest(dsc_remove_manifest, catch_failures: true) do |result|

0 commit comments

Comments
 (0)