Open SteveL-MSFT opened 10 months ago
Would this design pollute Get-Command
with DSC cmdlets?
Could you also explain how this design is simpler than a class based resource? If class based resources were defined as an interface it would simplify authorship and able to be implemented in PowerShell or C#. That could also allow for the removal of the PSDSC module by having all logic in the PowerShellGroup
.
@ThomasNieto good question. My expectation is that these DSC resources would not be used as general cmdlets so they wouldn't be exported as they would in a normal module.
The primary feedback we've gotten from customers is that class-based is simply too hard for them, but script functions is considered simple.
Note that we should still extend class-based resources to at least add export
support for those that prefer writing classes.
I've thought about this a lot over the last couple of years, especially since working on the Puppet.Dsc module that had to inspect and metaprogram handlers to use DSC Resources as "nearly native" Puppet resources. I encountered a lot of DevX challenges and inspected a ton of DSC Resource implementations along the way.
I filed a few discussions in the PSDSC repository on this, in particular:
Leaving those aside for a second, I think the most significant advantage class-based resources offer authors is the definition of the resource schema as class properties. I don't think people primarily struggle with defining resource properties, my experience and discussions with community members indicates that they primarily struggle with the way they're expected to implement class methods.
I've been playing around with some prototype ideas, but I see two main ways forward, with different options for each:
Personally, I favor the latter and having the dependency be on the PSDSC module itself - that module is already required for using Invoke-DscResource
and discovering existing resources, so as dependencies go it's (functionally, or nearly so) free. The downside to using PSDSC is WinPS compatibility, so it could be a separate module[^1].
If we're going the conventional route without runtime dependencies, the most effective model I can see is for authors to define resources as standalone scripts. The body of the script can be generated from a template and validated to a degree with AST parsing checks.
The alternative outlined above, which includes a mapping of parameters, may still require type definitions for complex use cases. With a conventional implementation, we could extract schemas from the script so they "just work" with the rest of the tooling, even though they're called by the PowerShell provider.
The downside to conventional resources is that they would need to be regenerated any time the conventions change - you can't "freely" get improvements for them. An upside is that if their runtime implementation is purely a script, you don't need to do anything special to integrate with them.
New-DscResourceDefinition
to generate the definition file, like Tailspin.dsc.definition.ps1
Get-TargetResource
Export-TargetResource
Test-TargetResource
Set-TargetResource
Build-DscResourceDefinition
to generate the self-contained script from their definition - this could also include updating the module manifest or defining a resource manifest. It should probably include a validation step to check the definition file, but authors should be able to run Test-DscResourceDefinition
separately for that purpose too.Interface definitions have a lot of benefits outlined in the discussions, including:
0
? We can't tell in the current model).Test
method (to mimic the synthetic test in V3 when using Invoke-DscResource
)Get
for v3.Aside from the static author-time analysis, a base class gives a lot of the same benefits.
I think a shared interface for resources is the most robust option, but I understand that it introduces a runtime dependency we want to avoid.
New-DscResource
to generate the script module or snippet to put in an existing script module.Author fills out the class definition, which inherits from the interface/base class.
Instead of defining the logic for the operations in class methods, the author defines the functions to call for those operations as static properties. All implementation logic lives in normal functions that take an instance of the class as input.
[^1]: For a separate module, it would probably make sense to ship that module with the PowerShell provider for DSCv3 - so you have some assurance that the version you pin to works with the provider implementation.
If the primary problem is authoring the schema, I wonder if the answer is simply tooling to generate JSON Schema whether it comes from a class definition or something else. Such a tool could be useful outside of DSC as well.
There's a two-way problem for non-class-based PSDSC resources - you have to define the schema and keep your implementation functions in sync with the schema. I definitely endorse being able to generate JSON Schema from PSDSC resource definitions (and generally for other objects/uses).
New PowerShell resources should support Export
scenario.
Summary of the new feature / enhancement
The feedback from customers is that authoring class-based resources is too complex and script-function resources require a MOF schema. Although we will continue to support existing script-function and class-based PS resources, we should consider them legacy and only via PSDSC module (with eventual 3.0 release). This also means legacy resources will never get support for
export
, for example.This proposes a new way to author DSCv3 resources in PS that does not require PSDSC module and instead is part of the PowerShellGroup resource and does not require authoring JSONSchema.
A goal is to not require any changes in PS itself to make this work so this will also work for WinPS5.1.
Proposed technical implementation details (optional)
The new PS resource model will be a module with cmdlets for
get
,set
,test
,export
. The mapping will be defined in the.psd1
within aPrivateData
section specifically for DSC. This means that these resources will still be discovered via$env:PSModulePath
.Most cases where the JSON structure is flat, the type and constraint information will simply be directly mapped to the parameters of a cmdlet. The
PowerShellGroup
resource will handle validating the input JSON maps to the cmdlet parameters.In some cases, the input JSON may require nested objects. To accommodate this, there are several options:
get
, etc... cmdlet have the parameter name match the "type" function name which simply accepts a hashtableKeys
parameterset.Here's an example for a simple object:
In this case, a
get
could look like:If we change this to have a nested object:
Then the required function would look like: