DSC icon indicating copy to clipboard operation
DSC copied to clipboard

Improve readability for nested resource instances in `dsc config` command output

Open michaeltlombardi opened this issue 9 months ago • 0 comments

Summary of the new feature / enhancement

As a user, I want to be able to review the output of the dsc config commands for configurations with nested instances and quickly understand the results without needing to compare multiple arrays for the same nested instance.

Current Context

This is a re-raising of #266, which was partially addressed.

Currently, when you use DSC to manage a configuration document containing nested resource instances, you get output that can be very difficult to parse, especially if you're not familiar with the data structure already.

The following details show the differences in output for:

  1. A flat configuration document containing adjacent, non-nested resource instances.
  2. A configuration document containing the same instances nested within a group resource instance.

Flat resources instances

In this example, the resources are defined adjacently, without being nested inside a group resource instance.

$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
  - type: Microsoft.DSC.Debug/Echo
    name: Foo
    properties:
      output: Example Foo
  - type: Microsoft.DSC.Debug/Echo
    name: Bar
    properties:
      output: Example Bar

When you use dsc config get to retrieve the current state, you can clearly see the result for every defined instance.

dsc config get result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Foo
  type: Microsoft.DSC.Debug/Echo
  result:
    actualState:
      output: Example Foo
- metadata: # elided for brevity
  name: Bar
  type: Microsoft.DSC.Debug/Echo
  result:
    actualState:
      output: Example Bar
messages: []
hadErrors: false

When you use dsc config test to verify the desired state, you can compare the desired state, actual state, boolean result, and list of differing properties for every defined instance.

dsc config test result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Foo
  type: Microsoft.DSC.Debug/Echo
  result:
    desiredState:
      output: Example Foo
    actualState:
      output: Example Foo
    inDesiredState: true
    differingProperties: []
- metadata: # elided for brevity
  name: Bar
  type: Microsoft.DSC.Debug/Echo
  result:
    desiredState:
      output: Example Bar
    actualState:
      output: Example Bar
    inDesiredState: true
    differingProperties: []
messages: []
hadErrors: false

When you use dsc config set to enforce the desired state, you can compare the state before the operation, the state after the operation, and the list of changed properties for every defined instance.

dsc config set result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Foo
  type: Microsoft.DSC.Debug/Echo
  result:
    beforeState:
      output: Example Foo
    afterState:
      output: Example Foo
    changedProperties: null
- metadata: # elided for brevity
  name: Bar
  type: Microsoft.DSC.Debug/Echo
  result:
    beforeState:
      output: Example Bar
    afterState:
      output: Example Bar
    changedProperties: null
messages: []
hadErrors: false`

Nested resource instances

In this example, the resources are defined adjacently as nested instances of a top-level group resource.

$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
  - type: Microsoft.DSC/Group
    name: Grouped Echo
    properties:
      $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
      resources:
        - type: Microsoft.DSC.Debug/Echo
          name: Foo
          properties:
            output: Example Foo
        - type: Microsoft.DSC.Debug/Echo
          name: Bar
          properties:
            output: Example Bar

When you use dsc config get to retrieve the current state, you can clearly see the result for every defined instance. Here, the result array for the group resource is an array of single-instance get results - it looks mostly like the output for the top-level instances, just nested within the group.

dsc config get result
metadata: # elided for brevity
results:
- metadata:
    Microsoft.DSC:
      duration: PT3.3259367S
  name: Grouped Echo
  type: Microsoft.DSC/Group
  result:
  - metadata: # elided for brevity
    name: Foo
    type: Microsoft.DSC.Debug/Echo
    result:
      actualState:
        output: Example Foo
  - metadata: # elided for brevity
    name: Bar
    type: Microsoft.DSC.Debug/Echo
    result:
      actualState:
        output: Example Bar
messages: []
hadErrors: false

When you use dsc config test to verify the desired state, it's difficult to understand the results. The group resource result has the desiredState, actualState, inDesiredState, and differingProperties fields, but:

  1. The desiredState is the desired state for the entire group
  2. The actualState contains the expected results for the nested instances.
  3. The inDesiredState value is false, which is inaccurate - the results show that the nested instances are both in the desired state. This appears to be caused by comparing the group resource's desired state to the test results for the nested instances.
  4. The differingProperties value isn't coherent - we don't expect differing properties for a group or adapter, which definitionally doesn't have it's own desired state, separate from the nested instances.
dsc config test result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Grouped Echo
  type: Microsoft.DSC/Group
  result:
    desiredState:
      $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
      resources:
      - type: Microsoft.DSC.Debug/Echo
        name: Foo
        properties:
          output: Example Foo
      - type: Microsoft.DSC.Debug/Echo
        name: Bar
        properties:
          output: Example Bar
    actualState:
    - metadata: # elided for brevity
      name: Foo
      type: Microsoft.DSC.Debug/Echo
      result:
        desiredState:
          output: Example Foo
        actualState:
          output: Example Foo
        inDesiredState: true
        differingProperties: []
    - metadata: # elided for brevity
      name: Bar
      type: Microsoft.DSC.Debug/Echo
      result:
        desiredState:
          output: Example Bar
        actualState:
          output: Example Bar
        inDesiredState: true
        differingProperties: []
    inDesiredState: false
    differingProperties:
    - resources
    - _exist
messages: []
hadErrors: false

When you use dsc config set to enforce the desired state, it's difficult to understand the results. The group resource result has the beforeState, afterState, and changedProperties fields, but:

  1. The beforeState seems to be an array containing get results for every nested instance/
  2. The afterState contains the expected set results for every nested instance.
  3. The changedProperties field is incoherent, again because group and adapter resources don't have a desired state separate from the nested instances. In this case, the field is at least an empty array, but probably shouldn't be included at all.
dsc config set result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Grouped Echo
  type: Microsoft.DSC/Group
  result:
    beforeState:
    - metadata: # elided for brevity
      name: Foo
      type: Microsoft.DSC.Debug/Echo
      result:
        actualState:
          output: Example Foo
    - metadata: # elided for brevity
      name: Bar
      type: Microsoft.DSC.Debug/Echo
      result:
        actualState:
          output: Example Bar
    afterState:
    - metadata: # elided for brevity
      name: Foo
      type: Microsoft.DSC.Debug/Echo
      result:
        beforeState:
          output: Example Foo
        afterState:
          output: Example Foo
        changedProperties: null
    - metadata: # elided for brevity
      name: Bar
      type: Microsoft.DSC.Debug/Echo
      result:
        beforeState:
          output: Example Bar
        afterState:
          output: Example Bar
        changedProperties: null
    changedProperties: []
messages: []
hadErrors: false

Proposed technical implementation details (optional)

I propose changing the results to the following for test and set for any resource instance containing nested instances:

Test Results

For resources with nested instances, I propose that the test result:

  1. Not include the differingProperties field.
  2. That we define an instanceResults or results field as an array containing the resource test result for every nested instance. I think instanceResults could help to semantically disambiguate the array, but I'm not attached to any particular name for this field.
  3. That the inDesiredState field be true if the inDesiredState field for every nested instance is true and otherwise false.
Group instance test result
metadata: # elided for brevity
name: Grouped Echo
type: Microsoft.DSC/Group
result:
  inDesiredState: true
  # Using a different property name to clearly signal the semantics of the
  # array, but it could be `results` if needed.
  instanceResults:
  - metadata: # elided for brevity
    name: Foo
    type: Microsoft.DSC.Debug/Echo
    result:
      desiredState:
        output: Example Foo
      actualState:
        output: Example Foo
      inDesiredState: true
      differingProperties: []
  - metadata: # elided for brevity
    name: Bar
    type: Microsoft.DSC.Debug/Echo
    result:
      desiredState:
        output: Example Bar
      actualState:
        output: Example Bar
      inDesiredState: true
      differingProperties: []
Full configuration result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Grouped Echo
  type: Microsoft.DSC/Group
  result:
    inDesiredState: true
    # Using a different property name to clearly signal the semantics of the
    # array, but it could be `results` if needed.
    instanceResults:
    - metadata: # elided for brevity
      name: Foo
      type: Microsoft.DSC.Debug/Echo
      result:
        desiredState:
          output: Example Foo
        actualState:
          output: Example Foo
        inDesiredState: true
        differingProperties: []
    - metadata: # elided for brevity
      name: Bar
      type: Microsoft.DSC.Debug/Echo
      result:
        desiredState:
          output: Example Bar
        actualState:
          output: Example Bar
        inDesiredState: true
        differingProperties: []
messages: []
hadErrors: false

Set Results

For resources with nested instances, I propose that the set result:

  1. Not include the changedProperties field.
  2. That we define an instanceResults or results field as an array containing the resource set result for every nested instance. I think instanceResults could help to semantically disambiguate the array, but I'm not attached to any particular name for this field.

I can also see an argument for having the result for the group be replaced by results, but that would cause it to deviate from typical resource instances. I think having it nested one layer as an array is okay in this instance.

We could also consider whether it would be useful to define a changedResources field, which returns the resource IDs for any nested resource instance that had a result with the changedProperties field containing one or more property name.

Group instance set result
metadata: # elided for brevity
name: Grouped Echo
type: Microsoft.DSC/Group
result:
  # Using a different property name to clearly signal the semantics of the
  # array, but it could be `results` if needed.
  instanceResults:
  - metadata: # elided for brevity
    name: Foo
    type: Microsoft.DSC.Debug/Echo
    result:
      beforeState:
        output: Example Foo
      afterState:
        output: Example Foo
      changedProperties: null
  - metadata: # elided for brevity
    name: Bar
    type: Microsoft.DSC.Debug/Echo
    result:
      beforeState:
        output: Example Bar
      afterState:
        output: Example Bar
      changedProperties: null
Full configuration result
metadata: # elided for brevity
results:
- metadata: # elided for brevity
  name: Grouped Echo
  type: Microsoft.DSC/Group
  result:
    # Using a different property name to clearly signal the semantics of the
    # array, but it could be `results` if needed.
    instanceResults:
    - metadata: # elided for brevity
      name: Foo
      type: Microsoft.DSC.Debug/Echo
      result:
        beforeState:
          output: Example Foo
        afterState:
          output: Example Foo
        changedProperties: null
    - metadata: # elided for brevity
      name: Bar
      type: Microsoft.DSC.Debug/Echo
      result:
        beforeState:
          output: Example Bar
        afterState:
          output: Example Bar
        changedProperties: null
messages: []
hadErrors: false

michaeltlombardi avatar Mar 27 '25 22:03 michaeltlombardi