Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PSAdapter cache updates #468

Merged
merged 6 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions powershell-adapter/Tests/powershellgroup.resource.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,44 @@ Describe 'PowerShell adapter resource tests' {
$res.actualState.result| % {$_.Name | Should -Not -BeNullOrEmpty}
}

It 'Verify that ClearCache works in PSAdapter' {
# generate the cache
$null = dsc resource list '*' -a Microsoft.DSC/PowerShell
# call the ClearCache operation
$scriptPath = Join-Path $PSScriptRoot '..' 'psDscAdapter' 'powershell.resource.ps1'
$null = & $scriptPath -Operation ClearCache
# verify that PSAdapter does not find the cache
dsc -l debug resource list '*' -a Microsoft.DSC/PowerShell 2> $TestDrive/tracing.txt
$LASTEXITCODE | Should -Be 0
"$TestDrive/tracing.txt" | Should -FileContentMatchExactly 'Cache file not found'
}

It 'Verify that a new PS Cache version results in cache rebuid' {
# generate the cache
$null = dsc resource list '*' -a Microsoft.DSC/PowerShell
# update the version in the cache file
$cacheFilePath = if ($IsWindows) {
# PS 6+ on Windows
Join-Path $env:LocalAppData "dsc\PSAdapterCache.json"
} else {
# either WinPS or PS 6+ on Linux/Mac
if ($PSVersionTable.PSVersion.Major -le 5) {
Join-Path $env:LocalAppData "dsc\WindowsPSAdapterCache.json"
} else {
Join-Path $env:HOME ".dsc" "PSAdapterCache.json"
}
}
$cache = Get-Content -Raw $cacheFilePath | ConvertFrom-Json
$cache.CacheSchemaVersion = 0
$jsonCache = $cache | ConvertTo-Json -Depth 90
New-Item -Force -Path $cacheFilePath -Value $jsonCache -Type File | Out-Null

# verify that a new PS Cache version results in cache rebuid
dsc -l debug resource list '*' -a Microsoft.DSC/PowerShell 2> $TestDrive/tracing.txt
$LASTEXITCODE | Should -Be 0
"$TestDrive/tracing.txt" | Should -FileContentMatchExactly 'Incompatible version of cache in file'
}

It 'Verify inheritance works in class-based resources' {

$r = dsc resource list '*' -a Microsoft.DSC/PowerShell
Expand Down
20 changes: 19 additions & 1 deletion powershell-adapter/psDscAdapter/powershell.resource.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0, HelpMessage = 'Operation to perform. Choose from List, Get, Set, Test, Export, Validate.')]
[ValidateSet('List', 'Get', 'Set', 'Test', 'Export', 'Validate')]
[ValidateSet('List', 'Get', 'Set', 'Test', 'Export', 'Validate', 'ClearCache')]
[string]$Operation,
[Parameter(Mandatory = $false, Position = 1, ValueFromPipeline = $true, HelpMessage = 'Configuration or resource input in JSON format.')]
[string]$jsonInput = '@{}'
Expand All @@ -27,6 +27,24 @@ function Write-DscTrace {
'PSPath=' + $PSHome | Write-DscTrace
'PSModulePath=' + $env:PSModulePath | Write-DscTrace

if ($Operation -eq 'ClearCache') {
$cacheFilePath = if ($IsWindows) {
# PS 6+ on Windows
Join-Path $env:LocalAppData "dsc\PSAdapterCache.json"
} else {
# either WinPS or PS 6+ on Linux/Mac
if ($PSVersionTable.PSVersion.Major -le 5) {
Join-Path $env:LocalAppData "dsc\WindowsPSAdapterCache.json"
} else {
Join-Path $env:HOME ".dsc" "PSAdapterCache.json"
}
}

'Deleting cache file ' + $cacheFilePath | Write-DscTrace
Remove-Item -Force -ea SilentlyContinue -Path $cacheFilePath
exit 0
}

if ('Validate' -ne $Operation) {
# write $jsonInput to STDERR for debugging
$trace = @{'Debug' = 'jsonInput=' + $jsonInput } | ConvertTo-Json -Compress
Expand Down
68 changes: 39 additions & 29 deletions powershell-adapter/psDscAdapter/psDscAdapter.psm1
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

$script:CurrentCacheSchemaVersion = 1

function Write-DscTrace {
param(
[Parameter(Mandatory = $false)]
Expand Down Expand Up @@ -242,47 +244,53 @@ function Invoke-DscCacheRefresh {
"Reading from Get-DscResource cache file $cacheFilePath" | Write-DscTrace

$cache = Get-Content -Raw $cacheFilePath | ConvertFrom-Json
$dscResourceCacheEntries = $cache.ResourceCache

if ($dscResourceCacheEntries.Count -eq 0) {
# if there is nothing in the cache file - refresh cache
if ($cache.CacheSchemaVersion -ne $script:CurrentCacheSchemaVersion) {
$refreshCache = $true
"Incompatible version of cache in file '"+$cache.CacheSchemaVersion+"' (expected '"+$script:CurrentCacheSchemaVersion+"')" | Write-DscTrace
} else {
$dscResourceCacheEntries = $cache.ResourceCache

"Filtered DscResourceCache cache is empty" | Write-DscTrace
}
else
{
"Checking cache for stale entries" | Write-DscTrace
if ($dscResourceCacheEntries.Count -eq 0) {
# if there is nothing in the cache file - refresh cache
$refreshCache = $true

foreach ($cacheEntry in $dscResourceCacheEntries) {
#"Checking cache entry '$($cacheEntry.Type) $($cacheEntry.LastWriteTimes)'" | Write-DscTrace -Operation Trace
"Filtered DscResourceCache cache is empty" | Write-DscTrace
}
else
{
"Checking cache for stale entries" | Write-DscTrace

$cacheEntry.LastWriteTimes.PSObject.Properties | ForEach-Object {

if (-not ((Get-Item $_.Name).LastWriteTime.Equals([DateTime]$_.Value)))
{
"Detected stale cache entry '$($_.Name)'" | Write-DscTrace
$refreshCache = $true
break
foreach ($cacheEntry in $dscResourceCacheEntries) {
#"Checking cache entry '$($cacheEntry.Type) $($cacheEntry.LastWriteTimes)'" | Write-DscTrace -Operation Trace

$cacheEntry.LastWriteTimes.PSObject.Properties | ForEach-Object {

if (-not ((Get-Item $_.Name).LastWriteTime.Equals([DateTime]$_.Value)))
{
"Detected stale cache entry '$($_.Name)'" | Write-DscTrace
$refreshCache = $true
break
}
}
}

if ($refreshCache) {break}
}
if ($refreshCache) {break}
}

"Checking cache for stale PSModulePath" | Write-DscTrace
"Checking cache for stale PSModulePath" | Write-DscTrace

$m = $env:PSModulePath -split [IO.Path]::PathSeparator | %{Get-ChildItem -Directory -Path $_ -Depth 1 -ea SilentlyContinue}
$m = $env:PSModulePath -split [IO.Path]::PathSeparator | %{Get-ChildItem -Directory -Path $_ -Depth 1 -ea SilentlyContinue}

$hs_cache = [System.Collections.Generic.HashSet[string]]($cache.PSModulePaths)
$hs_live = [System.Collections.Generic.HashSet[string]]($m.FullName)
$hs_cache.SymmetricExceptWith($hs_live)
$diff = $hs_cache
$hs_cache = [System.Collections.Generic.HashSet[string]]($cache.PSModulePaths)
$hs_live = [System.Collections.Generic.HashSet[string]]($m.FullName)
$hs_cache.SymmetricExceptWith($hs_live)
$diff = $hs_cache

"PSModulePath diff '$diff'" | Write-DscTrace
"PSModulePath diff '$diff'" | Write-DscTrace

if ($diff.Count -gt 0) {
$refreshCache = $true
if ($diff.Count -gt 0) {
$refreshCache = $true
}
}
}
}
Expand Down Expand Up @@ -330,6 +338,7 @@ function Invoke-DscCacheRefresh {
$cache.ResourceCache = $dscResourceCacheEntries
$m = $env:PSModulePath -split [IO.Path]::PathSeparator | %{Get-ChildItem -Directory -Path $_ -Depth 1 -ea SilentlyContinue}
$cache.PSModulePaths = $m.FullName
$cache.CacheSchemaVersion = $script:CurrentCacheSchemaVersion

# save cache for future use
# TODO: replace this with a high-performance serializer
Expand Down Expand Up @@ -494,6 +503,7 @@ class dscResourceCacheEntry {
}

class dscResourceCache {
[int] $CacheSchemaVersion
[string[]] $PSModulePaths
[dscResourceCacheEntry[]] $ResourceCache
}
Expand Down
57 changes: 42 additions & 15 deletions powershell-adapter/psDscAdapter/win_psDscAdapter.psm1
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

$script:CurrentCacheSchemaVersion = 1

function Write-DscTrace {
param(
[Parameter(Mandatory = $false)]
Expand Down Expand Up @@ -68,13 +70,16 @@ function Invoke-DscCacheRefresh {
"Reading from Get-DscResource cache file $cacheFilePath" | Write-DscTrace

$cache = Get-Content -Raw $cacheFilePath | ConvertFrom-Json
$dscResourceCacheEntries = $cache.ResourceCache

if ($dscResourceCacheEntries.Count -eq 0) {
# if there is nothing in the cache file - refresh cache
if ($cache.CacheSchemaVersion -ne $script:CurrentCacheSchemaVersion) {
$refreshCache = $true
"Incompartible version of cache in file '"+$cache.CacheSchemaVersion+"' (expected '"+$script:CurrentCacheSchemaVersion+"')" | Write-DscTrace
} else {
$dscResourceCacheEntries = $cache.ResourceCache

"Filtered DscResourceCache cache is empty" | Write-DscTrace
if ($dscResourceCacheEntries.Count -eq 0) {
# if there is nothing in the cache file - refresh cache
$refreshCache = $true
"Filtered DscResourceCache cache is empty" | Write-DscTrace
}
else
{
Expand All @@ -93,22 +98,42 @@ function Invoke-DscCacheRefresh {
}
}

if ($refreshCache) {break}
"Filtered DscResourceCache cache is empty" | Write-DscTrace
}
else
{
"Checking cache for stale entries" | Write-DscTrace

"Checking cache for stale PSModulePath" | Write-DscTrace
foreach ($cacheEntry in $dscResourceCacheEntries) {
"Checking cache entry '$($cacheEntry.Type) $($cacheEntry.LastWriteTimes)'" | Write-DscTrace -Operation Trace

$m = $env:PSModulePath -split [IO.Path]::PathSeparator | %{Get-ChildItem -Directory -Path $_ -Depth 1 -ea SilentlyContinue}
$cacheEntry.LastWriteTimes.PSObject.Properties | ForEach-Object {

if (-not ((Get-Item $_.Name).LastWriteTime.Equals([DateTime]$_.Value)))
{
"Detected stale cache entry '$($_.Name)'" | Write-DscTrace
$refreshCache = $true
break
}
}

$hs_cache = [System.Collections.Generic.HashSet[string]]($cache.PSModulePaths)
$hs_live = [System.Collections.Generic.HashSet[string]]($m.FullName)
$hs_cache.SymmetricExceptWith($hs_live)
$diff = $hs_cache
if ($refreshCache) {break}
}

"PSModulePath diff '$diff'" | Write-DscTrace
"Checking cache for stale PSModulePath" | Write-DscTrace

if ($diff.Count -gt 0) {
$refreshCache = $true
$m = $env:PSModulePath -split [IO.Path]::PathSeparator | %{Get-ChildItem -Directory -Path $_ -Depth 1 -ea SilentlyContinue}

$hs_cache = [System.Collections.Generic.HashSet[string]]($cache.PSModulePaths)
$hs_live = [System.Collections.Generic.HashSet[string]]($m.FullName)
$hs_cache.SymmetricExceptWith($hs_live)
$diff = $hs_cache

"PSModulePath diff '$diff'" | Write-DscTrace

if ($diff.Count -gt 0) {
$refreshCache = $true
}
}
}
}
Expand Down Expand Up @@ -223,6 +248,7 @@ function Invoke-DscCacheRefresh {
$cache.ResourceCache = $dscResourceCacheEntries
$m = $env:PSModulePath -split [IO.Path]::PathSeparator | %{Get-ChildItem -Directory -Path $_ -Depth 1 -ea SilentlyContinue}
$cache.PSModulePaths = $m.FullName
$cache.CacheSchemaVersion = $script:CurrentCacheSchemaVersion

# save cache for future use
# TODO: replace this with a high-performance serializer
Expand Down Expand Up @@ -472,6 +498,7 @@ class dscResourceCacheEntry {
}

class dscResourceCache {
[int] $CacheSchemaVersion
[string[]] $PSModulePaths
[dscResourceCacheEntry[]] $ResourceCache
}
Expand Down
Loading