PowerShell / DSC

This repo is for the DSC v3 project
MIT License
133 stars 22 forks source link

Unable to reuse `reference()` in set operation from get and test #389

Open michaeltlombardi opened 2 months ago

michaeltlombardi commented 2 months ago

Prerequisites

Steps to reproduce

When using the reference() function, you need to use dot-path notation to access the data from the result for a resource operation. For both get and test operations, you can use the actualState property of the return object to retrieve the state of the resource. However, for set operations, you need to use either the beforeState or afterState property.

This means that you can't define a reference() function once and reuse it across all operations - you need to define a separate configuration document.

You can reproduce this issue with this minimal configuration document:

# repro.dsc.config.yaml
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json
resources:
- name: current user registry
  type: Microsoft.Windows/Registry
  properties:
    keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
    valueName: ProductName
    _exist: true
- name: Echo Reference
  type: Test/Echo
  properties:
    output: "[reference(resourceId('Microsoft.Windows/Registry', 'current user registry')).actualState.valueName]"
  dependsOn:
    - "[resourceId('Microsoft.Windows/Registry', 'current user registry')]"

Steps:

$config = Get-Content -Raw -Path ./repro.dsc.config.yaml
$config | dsc config get
$config | dsc config test
$config | dsc config set

Proposed fix

The following options occur to me:

  1. Do the step-in for actualState and afterState on behalf of the users, instead of requiring them to manually step in with dot-notation - so instead of reference(...).actualState.valueName, the user would write reference(...).valueName. Are there cases where users will want to get at values other than the canonical state of the resource with a reference?
  2. Rename the actualState and/or afterState properties to use the same name. I'm not sure I see a good option here, all of the new names I can think of are less descriptive of what's being returned.
  3. Provide an error handler that specifically tries afterState for the set operation if it can't find the actualState key. This would quietly enable users to define one reference and reuse it across all operations, but it's a little bit non-obvious and adds a special code path.

Expected behavior

PS> $config | dsc config get
results:
- name: current user registry
  type: Microsoft.Windows/Registry
  result:
    actualState:
      $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
      keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
      valueName: ProductName
      valueData:
        String: Windows 10 Enterprise
- name: Echo Reference
  type: Test/Echo
  result:
    actualState:
      output: ProductName
messages: []
hadErrors: false
PS> $config | dsc config test
results:
- name: current user registry
  type: Microsoft.Windows/Registry
  result:
    desiredState:
      keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
      valueName: ProductName
      _exist: true
    actualState:
      $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
      keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
      valueName: ProductName
      valueData:
        String: Windows 10 Enterprise
      _exist: true
      _inDesiredState: true
    inDesiredState: true
    differingProperties: []
- name: Echo Reference
  type: Test/Echo
  result:
    desiredState:
      output: ProductName
    actualState:
      output: ProductName
    inDesiredState: true
    differingProperties: []
messages: []
hadErrors: false
PS> $config | dsc config set
results:
- name: current user registry
  type: Microsoft.Windows/Registry
  result:
    beforeState:
      $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
      keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
      valueName: ProductName
      valueData:
        String: Windows 10 Enterprise
    afterState:
      $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
      keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
      valueName: ProductName
    changedProperties: []
- name: Echo Reference
  type: Test/Echo
  result:
    beforeState:
      output: ProductName
    afterState:
      output: ProductName
    changedProperties: null
messages: []
hadErrors: false

Actual behavior

PS> $config | dsc config set

2024-04-09T15:36:27.710767Z ERROR dsc::subcommand: 95: Error: Parser: Member 'actualState' not found

Error details

2024-04-09T15:36:27.710767Z ERROR dsc::subcommand: 95: Error: Parser: Member 'actualState' not found

Environment data

Name                           Value
----                           -----
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Microsoft Windows 10.0.22631
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Version

Latest build from main

Visuals

No response