3

假设我有两个这样的块:

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'
        }
    }
}

我构建了一个执行类似操作的测试,但无论 File 资源的测试输出如何,似乎 Service 资源都会被执行 - 也就是说,如果它实际上对文件做了任何事情。

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.

除了人为的例子,我怎样才能让脚本资源只有在文件资源确实做了一些事情的情况下才执行?

我的用例是检查远程位置的文件是否已更改,如果是,请将其复制到本地计算机,然后重新启动服务。如果文件没有更改,我显然不想重新启动服务,但我看不到一个好的幂等方法,因为正在使用哈希测试文件 - 我必须拥有我的服务重新启动步骤执行相同的文件哈希检查。

4

1 回答 1

3

我认为 DSC 中没有内置任何东西可以让一个资源检测“Set-TargetResource”函数是否实际上是在同一配置运行中为不同的资源执行的。

但是,以下脚本资源将执行您想要的操作,但它们使用全局脚本级变量进行通信,因此如果您在单个 DSC 中配置多个服务,它们将中断。ConfigureService 脚本资源更新本地配置文件并设置一个标志,RestartService 资源读取该标志以检查是否进行了更改。它有点脏,但它有效。

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";
    }
}

或者,只需将其全部整合到一个资源中。如果您想将其重新用于一项以上的服务,您可以将其移动到成熟的 ServiceConfiguration 自定义资源中。

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";
    }
}
于 2014-09-29T21:51:46.963 回答