Reputation: 1002
Say I've got two blocks like this:
Configuration TestConfig
{
Node ('localhost') {
File foo {
DestinationPath = 'C:\foo.txt'
Contents = 'Bar'
}
Script dothing {
SetScript = {'Baz' | set-content C:\foo.txt}
TestScript = {return $false}
GetScript = {
return @{
GetScript = ''
SetScript = ''
TestScript = ''
Credential = $Credential
Result = (Invoke-Expression -Command $TestScript)
}
}
DependsOn = '[File]foo'
}
}
}
I built a test that does something like this, but it seems like the Service resource gets executed regardless of the File resource's test output - that is, if it actually did anything to the file.
VERBOSE: [MACHINENAME]: LCM: [ Start Set ]
VERBOSE: [MACHINENAME]: LCM: [ Start Resource ] [[File]foo]
VERBOSE: [MACHINENAME]: LCM: [ Start Test ] [[File]foo]
VERBOSE: [MACHINENAME]: [[File]foo] The destination object was found and no action is required.
VERBOSE: [MACHINENAME]: LCM: [ End Test ] [[File]foo] in 0.0040 seconds.
VERBOSE: [MACHINENAME]: LCM: [ Skip Set ] [[File]foo]
VERBOSE: [MACHINENAME]: LCM: [ End Resource ] [[File]foo]
VERBOSE: [MACHINENAME]: LCM: [ Start Resource ] [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM: [ Start Test ] [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM: [ End Test ] [[Script]dothing] in 0.0050 seconds.
VERBOSE: [MACHINENAME]: LCM: [ Start Set ] [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM: [ End Set ] [[Script]dothing] in 0.0060 seconds.
VERBOSE: [MACHINENAME]: LCM: [ End Resource ] [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM: [ End Set ]
VERBOSE: [MACHINENAME]: LCM: [ End Set ] in 0.0390 seconds.
Contrived example aside, how can I only have the Script resource execute only if the File resource actually did something?
My use case here is checking to see if a file has changed in a remote location, and if so, copy it to the local machine, then restart a service. I obviously don't want to restart the service if the file hasn't changed, but I can't see a good idempotent way to do that, since the file is being tested using a hash - I'd have to have my service restart step do the same file hash check.
Upvotes: 3
Views: 4130
Reputation: 10075
I don't think there's anything natively built into DSC that lets one resource detect whether the "Set-TargetResource" function was actually executed for a different resource in the same configuration run.
However, the following Script resources will do what you want, but they make use of a global script-level variable to communicate so they'll break if you've got more than one service to configure in a single DSC. The ConfigureService Script resource updates the local config file and sets a flag that the RestartService resource reads to check if a change was made. It's a bit dirty, but it works.
Script ConfigureService {
GetScript = { return $null; }
TestScript = {
# compare remote and local file contents and return
# $true if they match, or $false if they're different
$source = "D:\temp\dsctest\source.txt";
$target = "D:\temp\dsctest\target.txt";
$isMatch = [System.IO.File]::ReadAllText($target) -eq [System.IO.File]::ReadAllText($source);
# set a flag for the RestartService resource to read
$script:serviceChanged = -not $isMatch;
write-verbose "isMatch = $isMatch";
return $isMatch;
}
SetScript = {
# overwrite the local file
$source = "D:\temp\dsctest\source.txt";
$target = "D:\temp\dsctest\target.txt";
$content = [System.IO.File]::ReadAllText($source);
write-verbose "overwriting config";
[System.IO.File]::WriteAllText($target, $content);
}
}
Script RestartService {
DependsOn = "[Script]ConfigureService"
GetScript = { return $null; }
TestScript = {
write-verbose "serviceChanged = $($script:serviceChanged)";
return -not $script:serviceChanged;
}
SetScript = {
# restart the service
write-verbose "restarting service";
}
}
Alternatively just roll it all into a single resource. If you then want to re-use this for more than one service you could move it into a fully-fledged ServiceConfiguration custom resource.
Script ConfigureService {
GetScript = { return $null; }
TestScript = {
# compare remote and local file contents and return
# $true if they match, or $false if they're different
$source = "D:\temp\dsctest\source.txt";
$target = "D:\temp\dsctest\target.txt";
$isMatch = [System.IO.File]::ReadAllText($target) -eq [System.IO.File]::ReadAllText($source);
write-verbose "isMatch = $isMatch";
return $isMatch;
}
SetScript = {
# overwrite the local file
$source = "D:\temp\dsctest\source.txt";
$target = "D:\temp\dsctest\target.txt";
$content = [System.IO.File]::ReadAllText($source);
write-verbose "overwriting config";
[System.IO.File]::WriteAllText($target, $content);
# restart the service
write-verbose "restarting service";
}
}
Upvotes: 3