diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fac5786c..62f469494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,28 +81,33 @@ changes since the last release, see the [diff on GitHub][unreleased]. [actual configuration set operation][ur-ab], except that the metadata field [executionType][ur-ac] is set to `WhatIf` instead of `Actual`. - In this release, the generated output is synthetic, based on the results of the resources' `test` - operation. In the future, resources will be able to participate in what-if operations, reporting - more specifically how they will change the system. For example, participating resources could - indicate whether an actual set operation will require a reboot or whether the current user has -the correct permissions to manage that resource instance. + By default, the generated output is synthetic, based on the results of the resources' `test` + operation. Resources can define the [whatIf][ur-ad] property in their resource manifest to + participate in what-if operations, reporting more specifically how they will change the system. + For example, participating resources could indicate whether an actual set operation will require + a reboot or whether the current user has the correct permissions to manage that resource + instance. + + Participating resources have the [WhatIf capability][ur-ae].
Related work items - Issues: [#70][#70] - - PRs: [#400][#400] + - PRs: + - [#400][#400] + - [#441][#441]
-- Added support for [importer resources][ur-ad]. These resources resolve external sources to a +- Added support for [importer resources][ur-af]. These resources resolve external sources to a nested DSC Configuration document. The resolved instances are processed as nested resource instances. This required some updates to the schemas, all backwards-compatible: - - Added a new [resourceKind][ur-ae] named `Import`. - - Added the [resolve][ur-af] command to resource manifests. - - Added the new [`Resolve`][ur-ag] capability, returned in the output for the + - Added a new [resourceKind][ur-ag] named `Import`. + - Added the [resolve][ur-ah] command to resource manifests. + - Added the new [`Resolve`][ur-ai] capability, returned in the output for the [dsc resource list][cmd-rlist] command when DSC discovers an importer resource.
Related work items @@ -232,10 +237,12 @@ the correct permissions to manage that resource instance. [ur-aa]: ./docs/reference/cli/config/set.md#-w---what-if [ur-ab]: ./docs/reference/schemas/outputs/config/set.md [ur-ac]: ./docs/reference/schemas/metadata/Microsoft.DSC/properties.md#executiontype -[ur-ad]: ./docs/reference/schemas/definitions/resourceKind.md#importer-resources -[ur-ae]: ./docs/reference/schemas/definitions/resourceKind.md -[ur-af]: ./docs/reference/schemas/resource/manifest/resolve.md -[ur-ag]: ./docs/reference/schemas/outputs/resource/list.md#capability-resolve +[ur-ad]: ./docs/reference/schemas/resource/manifest/whatif.md +[ur-ae]: ./docs/reference/schemas/outputs/resource/list.md#capability-whatif +[ur-af]: ./docs/reference/schemas/definitions/resourceKind.md#importer-resources +[ur-ag]: ./docs/reference/schemas/definitions/resourceKind.md +[ur-ah]: ./docs/reference/schemas/resource/manifest/resolve.md +[ur-ai]: ./docs/reference/schemas/outputs/resource/list.md#capability-resolve [ur-fa]: ./docs/reference/schemas/resource/manifest/root.md#exitcodes ## [v3.0.0-preview.7][release-v3.0.0-preview.7] - 2024-04-22 @@ -1505,6 +1512,7 @@ For the full list of changes in this release, see the [diff on GitHub][compare-v [#432]: https://github.com/PowerShell/DSC/issues/432 [#434]: https://github.com/PowerShell/DSC/issues/434 [#438]: https://github.com/PowerShell/DSC/issues/438 +[#441]: https://github.com/PowerShell/DSC/issues/441 [#45]: https://github.com/PowerShell/DSC/issues/45 [#49]: https://github.com/PowerShell/DSC/issues/49 [#57]: https://github.com/PowerShell/DSC/issues/57 diff --git a/docs/reference/schemas/outputs/resource/list.md b/docs/reference/schemas/outputs/resource/list.md index 6970ffb65..a9d23a7f5 100644 --- a/docs/reference/schemas/outputs/resource/list.md +++ b/docs/reference/schemas/outputs/resource/list.md @@ -85,15 +85,15 @@ optional and depend on the resource. The following list describes the available capabilities for a resource: -- `Get` - The resource supports retrieving the current state of an +- `Get` - The resource supports retrieving the current state of an instance. All DSC Resources must have this capability. A resource has this capability when it defines the mandatory [get][07] property in its resource manifest. -- `Set` - The resource supports enforcing the desired state of an +- `Set` - The resource supports enforcing the desired state of an instance. A resource has this capability when it defines the [set][08] property in its resource manifest. Resources without this capability can't be used with the [dsc resource set][09] or [dsc config set][10] commands unless they're in a [Microsoft.DSC/Assertion][11] group as a nested instance. -- `SetHandlesExist` - The resource supports the +- `SetHandlesExist` - The resource supports the [_exist property][12] directly. A resource has this capability when it defines the [handlesExist][13] property as `true` in the definition of the [set][08] command property in its resource manifest. @@ -106,28 +106,43 @@ The following list describes the available capabilities for a resource: If the resource doesn't have this capability or the `Delete` capability, DSC raises an error when an instance defines `_exist` as `false`. -- `Test` - The resource supports validating the desired state of an +- `WhatIf` - The resource supports returning explicit information + about how it will modify state when a user calls [dsc config set][10] with the [--what-if][15] + option. A resource has this capability when it defines the [What-if method][16] in its resource + manifest. + + When a resource has this capability, DSC calls the defined command with its arguments when a + user executes the `dsc config set` command with the `--what-if` option. + + When a resource doesn't have this capability, DSC synthesizes how the resource will change and + instance by converting the `Test` result for the instance into a `Set` result. The synthetic + operation can't indicate potential issues or changes that can't be determined by comparing the + result of the `Test` operation against the resource's desired state. For example, the credentials + used to test a resource might be valid for that operation, but not have permissions to actually + modify the system state. Only a resource with this capability can fully report whether and how + the resource will change system state. +- `Test` - The resource supports validating the desired state of an instance against the current state of the instance. A resource has this capability when it - defines the [test][15] property in its resource manifest. + defines the [test][17] property in its resource manifest. If a resource doesn't have the `Test` capability, DSC uses a synthetic test for instances of the resource. The synthetic test compares each property for the desired state of an instance against the actual state. The synthetic test uses strict, case-sensitive equivalence. If the desired state for a property and the actual state aren't the same, DSC marks the property as out of the desired state. -- `Delete` - The resource supports removing an instance. A resource +- `Delete` - The resource supports removing an instance. A resource has this capability when it defines the [delete][14] property in its resource manifest. This capability isn't mutually exclusive with the `SetHandlesExist` property. A resource can handle - the `_exist` property in set operations and be called directly with [dsc resource delete][16] to + the `_exist` property in set operations and be called directly with [dsc resource delete][18] to remove an instance. -- `Export` - The resource supports enumerating every instance of the - resource. A resource has this capability when it defines the [export][17] property in its resource - manifest. Only resources with this capability are usable with the [dsc resource export][18] and - [dsc config export][19] commands. -- `Resolve` - The resource supports resolving nested resource +- `Export` - The resource supports enumerating every instance of + the resource. A resource has this capability when it defines the [export][19] property in its + resource manifest. Only resources with this capability are usable with the + [dsc resource export][20] and [dsc config export][21] commands. +- `Resolve` - The resource supports resolving nested resource instances from an external source. A resource has this capability when it defines the - [resolve][20] property in its resource manifest. This functionality is primarily used by - [importer resources][21]. + [resolve][22] property in its resource manifest. This functionality is primarily used by + [importer resources][23]. ```yaml Type: array @@ -215,7 +230,7 @@ Required: true Represents the values defined in the resource's manifest. This value is `null` for resources that aren't command-based. For more information on the value for this property, see -[Command-based DSC Resource manifest schema reference][22]. +[Command-based DSC Resource manifest schema reference][24]. ```yaml Type: [object, 'null'] @@ -237,11 +252,13 @@ Required: true [12]: ../../resource/properties/exist.md [13]: ../../resource/manifest/set.md#handlesexist [14]: ../../resource/manifest/delete.md -[15]: ../../resource/manifest/test.md -[16]: ../../../cli/resource/delete.md -[17]: ../../resource/manifest/export.md -[18]: ../../../cli/resource/export.md -[19]: ../../../cli/config/export.md -[20]: ../../resource/manifest/resolve.md -[21]: ../../definitions/resourceKind.md#importer-resources -[22]: ../../resource/manifest/root.md +[15]: ../../../cli/config/set.md#-w---what-if +[16]: ../../resource/manifest/whatif.md +[17]: ../../resource/manifest/test.md +[18]: ../../../cli/resource/delete.md +[19]: ../../resource/manifest/export.md +[20]: ../../../cli/resource/export.md +[21]: ../../../cli/config/export.md +[22]: ../../resource/manifest/resolve.md +[23]: ../../definitions/resourceKind.md#importer-resources +[24]: ../../resource/manifest/root.md diff --git a/docs/reference/schemas/resource/manifest/whatif.md b/docs/reference/schemas/resource/manifest/whatif.md new file mode 100644 index 000000000..ed5054edb --- /dev/null +++ b/docs/reference/schemas/resource/manifest/whatif.md @@ -0,0 +1,283 @@ +--- +description: JSON schema reference for the 'whatIf' property in a DSC Resource manifest +ms.date: 01/17/2024 +ms.topic: reference +title: DSC Resource manifest whatIf property schema reference +--- + +# DSC Resource manifest whatIf property schema reference + +## Synopsis + +Defines how to indicate whether and how the set command will modify an instance. + +## Metadata + +```yaml +SchemaDialect: https://json-schema.org/draft/2020-12/schema +SchemaID: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json +Type: object +``` + +## Description + +When enforcing a configuration document with the [dsc config set][01] command, users can specify +the [--what-if][02] option to see whether and how resources will change system state without +actually doing so. This property defines how DSC can invoke the resource to return that information +directly. + +When this property isn't defined, DSC synthesizes this behavior by converting the result of a test +operation against the resource into a set result. The synthetic result can only indicate how the +operation will change the resource properties. It can't indicate whether the `set` operation will +fail due to invalid parameters or which read-only properties the resource will return from the +operation. The following list describes a few cases where a synthetic what-if result won't return +sufficient information to the user: + +- A resource requiring a credential parameter might successfully test the instance but not have + permissions to modify it. In this case, the user might run `dsc config set --what-if` and see an + apparently successful prediction for the resource. Then, when they run the command without the + `--what-if` option, the resource raises an error that the user has to investigate. If any other + resources applied successfully before the instance that failed, the system might be left in a + partially-configured state. +- A resource with a dependency service won't be able to report whether that service needs to be + restarted from a synthetic result. After reviewing the impact of the configuration based on the + what-if result, a user might then inadvertently restart a service or leave the configuration in a + partially-configured state until that service is rebooted. + +If your resource uses parameters or returns read-only properties from a `set` operation, define this +method to ensure your users get the best information about whether and how the resource will modify +system state in what-if mode. + +DSC sends data to the command in three ways: + + 1. When `input` is `stdin`, DSC sends the data as a string representing the data as a compressed + JSON object without spaces or newlines between the object properties. + 1. When `input` is `env`, DSC sends the data as environment variables. It creates an environment + variable for each property in the input data object, using the name and value of the property. + 1. When the `args` array includes a JSON input argument definition, DSC sends the data as a + string representing the data as a compressed JSON object to the specified argument. + +If you don't define the `input` property and don't define a JSON input argument, DSC can't pass the +input JSON to the resource. You can only define one JSON input argument for a command. + +You must define the `input` property, one JSON input argument in the `args` property array, or +both. + +## Examples + +### Example 1 - Full definition + +```json +"set": { + "executable": "my_app", + "args": [ + "config", + "set", + "--what-if" + ], + "input": "stdin", + "return": "state" +} +``` + +It defines `executable` as `my_app`, rather than `my_app.exe`. The extension isn't required when +the operating system recognizes the command as an executable. + +The manifest defines three arguments, `config`, `set`, and `--what-if`. The value of the `input` +property indicates that the `whatIf` command expects its input as a JSON blob from `stdin`. + +Combined with the value for `executable`, DSC calls the what-if method for this resource by +running: + +```sh +{ ... } | my_app config set --what-if +``` + +The manifest defines `return` as `state`, indicating that it only returns the expected final state +of the resource after the `set` method runs. DSC compares the desired state to the return data of +this resource to identify which of the resource's properties the `set` method will enforce, if any. + +## Required Properties + +The `whatIf` definition must include these properties: + +- [executable](#executable) + +## Properties + +### executable + +The `executable` property defines the name of the command to run. The value must be the name of a +command discoverable in the system's `PATH` environment variable or the full path to the command. A +file extension is only required when the command isn't recognizable by the operating system as an +executable. + +```yaml +Type: string +Required: true +``` + +### args + +The `args` property defines the list of arguments to pass to the command. The arguments can be any +number of strings. If you want to pass the JSON object representing the property bag for the +resource to an argument, you can define a single item in the array as a JSON object, indicating the +name of the argument with the `jsonInputArg` string property and whether the argument is mandatory +for the command with the `mandatory` boolean property. + +```yaml +Type: array +Required: false +Default: [] +Type: [string, object(JSON Input Argument)] +``` + +#### String arguments + +Any item in the argument array can be a string representing a static argument to pass to the +command, like `config` or `--format`. + +```yaml +Type: string +``` + +#### JSON input argument + +Defines an argument for the command that accepts the JSON input object as a string. DSC passes the +JSON input to the named argument when available. A JSON input argument is defined as a JSON object +with the following properties: + +- `jsonInputArg` (required) - the argument to pass the JSON data to for the command, like `--input`. +- `mandatory` (optional) - Indicate whether DSC should always pass the argument to the command, + even when there's no JSON input for the command. In that case, DSC passes an empty string to the + JSON input argument. + +You can only define one JSON input argument per arguments array. + +If you define a JSON input argument and an `input` kind for a command, DSC sends the JSON data both +ways: + +- If you define `input` as `env` and a JSON input argument, DSC sets an environment variable for + each property in the JSON input and passes the JSON input object as a string to the defined + argument. +- If you define `input` as `stdin` and a JSON input argument, DSC passes the JSON input over stdin + and as a string to the defined argument. +- If you define a JSON input argument without defining the `input` property, DSC only passes the + JSON input as a string to the defined argument. + +If you don't define the `input` property and don't define a JSON input argument, DSC can't pass the +input JSON to the resource. This makes the manifest invalid. You must define the `input` property, +a JSON input argument in the `args` property array, or both. + +```yaml +Type: object +RequiredProperties: [jsonInputArg] +``` + +### input + +The `input` property defines how to pass input to the resource. If this property isn't defined and +the definition doesn't define a [JSON input argument](#json-input-argument), DSC doesn't send any +input to the resource when invoking the `whatIf` operation. + +The value of this property must be one of the following strings: + +- `env` - Indicates that the resource expects the properties of an instance to be specified as + environment variables with the same names and casing. + + This option only supports the following data types for instance properties: + + - `boolean` + - `integer` + - `number` + - `string` + - `array` of `integer` values + - `array` of `number` values + - `array` of `string` values + + For non-array values, DSC sets the environment variable to the specified value as-is. When the + data type is an array of values, DSC sets the environment variable as a comma-delimited string. + For example, the property `foo` with a value of `[1, 2, 3]` is saved in the `foo` environment + variable as `"1,2,3"`. + + If the resource needs to support complex properties with an `object` value or multi-type arrays, + set this to `stdin` instead. +- `stdin` - Indicates that the resource expects a JSON blob representing an instance from `stdin`. + The JSON must adhere to the instance schema for the resource. + +```yaml +Type: string +Required: false +ValidValues: [env, stdin] +``` + +### implementsPretest + +The `implementsPretest` property defines whether the resource tests whether the instance is in the +desired state internally before enforcing the desired state. Set this property to `true` when the +resource tests the instance as part of the `set` operation. Set this property to `false` when it +doesn't. In most cases, this value should be set the same as the `implementsPretest` property in +the definition for the [set method][03] in the resource manifest. + +When this value is `false`, it indicates that users should always call `dsc resource test` against +the instance before invoking the `dsc resource set` command against the resource. + +The default value is `false`. + +```yaml +Type: boolean +Required: false +Default: false +``` + +### handlesExist + +The `handlesExist` property defines whether the resource has built-in handling for the +[_exist][04] property in the `set` operation. The default value is `false`. In most cases, this +value should be set the same as the `implementsPretest` property in the definition for the +[set method][03] in the resource manifest. + +Set this property to `true` when the resource meets the following implementation requirements: + +- The resource's [instance schema][05] defines the `_exist` property as a valid instance property. +- The resource's `set` command handles creating, updating, and deleting an instance based on the + current state of the instance and the value of the `_exist` property in the desired state. + +When this property is set to `true`, the resource indicates that it has the [SetHandlesExist][06] +[capability][07]. When processing resources with the `SetHandlesExist` capability in a +configuration, DSC calls the `set` operation for the resource when an instance defines `_exist` as +`false`. Without this capability, a resource must define the [delete][08] operation to support +removing instances of the resource. + +If a resource manifest doesn't define this property as `true` and doesn't define the `delete` +operation, DSC raises an error when it encounters an instance of the resource with `_exist` set to +`false`. + +### return + +The `return` property defines how DSC should process the output for this method. The value of this +property must be one of the following strings: + +- `state` - Indicates that the resource returns only the instance's expected final state after the + set operation as a JSON blob. +- `stateAndDiff` - Indicates that the resource returns the instance's expected final state and an + array of property names that the resource modified. + +The default value is `state`. + +```yaml +Type: string +Required: false +Default: state +ValidValues: [state, stateAndDiff] +``` + + +[01]: ../../../cli/config/set.md +[02]: ../../../cli/config/set.md#-w---what-if +[03]: ./set.md +[04]: ../properties/exist.md +[05]: ./root.md#schema-1 +[06]: ../../outputs/resource/list.md#capability-sethandlesexist +[07]: ../../outputs/resource/list.md#capabilities +[08]: ./delete.md diff --git a/schemas/2024/04/bundled/outputs/resource/list.json b/schemas/2024/04/bundled/outputs/resource/list.json index c678e738f..9b98affa6 100644 --- a/schemas/2024/04/bundled/outputs/resource/list.json +++ b/schemas/2024/04/bundled/outputs/resource/list.json @@ -24,6 +24,7 @@ "Get", "Set", "SetHandlesExist", + "WhatIf", "Test", "Delete", "Export", @@ -200,6 +201,9 @@ "set": { "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.set.json" }, + "whatIf": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json" + }, "test": { "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json" }, @@ -441,6 +445,89 @@ } ] }, + "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json", + "title": "What-if method", + "description": "Defines how DSC must call the DSC Resource to indicate whether and how the set command will modify an instance and how to process the output from the DSC Resource.", + "type": "object", + "required": [ + "executable" + ], + "properties": { + "executable": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/commandExecutable.json" + }, + "args": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/commandArgs.json" + }, + "input": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/inputKind.json" + }, + "implementsPretest": { + "title": "Resource Performs Pre-Test", + "description": "Defines whether the DSC Resource performs its own test to ensure idempotency when calling the `set --what-if` command. Set this value to `true` if the DSC Resource tests input before processing how it will modify system state.", + "type": "boolean", + "default": false + }, + "handlesExist": { + "title": "Resource handles _exist property", + "description": "Defines whether the DSC Resource has its own built-in handling for the `_exist` common property. Set this value to `true` if the DSC Resource handles instance deletion internally when receiving a `set --what-if` command where the instance defines the `_exist` property as `false`.", + "type": "boolean", + "default": false + }, + "return": { + "description": "Defines whether the command returns a JSON blob of the DSC Resource's expected state after a set operation in what-if mode or the state and an array of the properties the DSC Resource would modify.", + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/returnKind.json" + } + }, + "oneOf": [ + { + "required": [ + "input" + ], + "not": { + "properties": { + "args": { + "contains": { + "type": "object" + } + } + } + } + }, + { + "not": { + "required": [ + "input" + ] + }, + "properties": { + "args": { + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + }, + { + "required": [ + "input" + ], + "properties": { + "args": { + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + } + ] + }, "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json", diff --git a/schemas/2024/04/bundled/outputs/resource/list.vscode.json b/schemas/2024/04/bundled/outputs/resource/list.vscode.json index b0fa46dad..994bf9d8d 100644 --- a/schemas/2024/04/bundled/outputs/resource/list.vscode.json +++ b/schemas/2024/04/bundled/outputs/resource/list.vscode.json @@ -24,6 +24,7 @@ "Get", "Set", "SetHandlesExist", + "WhatIf", "Test", "Delete", "Export", @@ -548,6 +549,9 @@ "set": { "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/resource/manifest.set.json" }, + "whatIf": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json" + }, "test": { "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json" }, @@ -895,6 +899,142 @@ } ] }, + "manifest.whatIf.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json", + "title": "What-if method", + "description": "Defines how DSC must call the DSC Resource to indicate whether and how the set command will modify an instance and how to process the output from the DSC Resource.", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines how DSC must call the DSC Resource to indicate whether and how the set command will\nmodify an instance and how to process the output from the DSC Resource. If a resource doesn't\ndefine this method in the manifest, DSC synthesizes this behavior by converting the result of\nthe test operation for the resource into the [set result][02].\n\nThis method definition has the same structure as the [set method][03] in the resource manifest.\n\nDSC sends data to the command in three ways:\n\n1. When `input` is `stdin`, DSC sends the data as a string representing the data as a compressed\n JSON object without spaces or newlines between the object properties.\n1. When `input` is `env`, DSC sends the data as environment variables. It creates an environment\n variable for each property in the input data object, using the name and value of the property.\n1. When the `args` array includes a JSON input argument definition, DSC sends the data as a string\n representing the data as a compressed JSON object to the specified argument.\n\nIf you don't define the `input` property and don't define a JSON input argument, DSC can't pass\nthe input JSON to the resource. You can only define one JSON input argument for a command.\n\nYou must define the `input` property, one JSON input argument in the `args` property array, or\nboth.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true\n[02]: https://learn.microsoft.com/powershell/dsc/reference/schemas/outputs/resource/set?view=dsc-3.0&preserve-view=true\n[03]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/set?view=dsc-3.0&preserve-view=true\n", + "type": "object", + "required": [ + "executable" + ], + "properties": { + "executable": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/commandExecutable.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines the name of the command to run. The value must be the name of a command discoverable\nin the system's `PATH` environment variable or the full path to the command. A file extension\nis only required when the command isn't recognizable by the operating system as an\nexecutable.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#executable\n" + }, + "args": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/commandArgs.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines an array of strings to pass as arguments to the command. DSC passes the arguments to\nthe command in the order they're specified.\n\nFor example, the given the following definition:\n\n```json\n{\n \"executable\": \"myresource\",\n \"args\": [\"config\", \"set\", \"--what-if\"],\n}\n```\n\nDSC invokes the command for the resource as:\n\n```bash\nmyresource config set --what-if\n```\n\nIf you want to pass the JSON object representing the property bag for a resource instance to\nan argument, you can define a single item in the array as a JSON object. Indicate the name of\nthe argument with the `jsonInputArg` string property and whether the argument is mandatory\nfor the command with the `mandatory` boolean property.` When the `mandatory` property is\ndefined as `true`, DSC passes an empty string to the argument when no JSON input is\navailable. When the `mandatory` property is undefined or defined as `false`, DSC doesn't pass\nthe argument at all when no JSON input is available. The default value for the `mandatory`\nproperty is `false`.\n\nFor example, given the following definition:\n\n```json\n{\n \"executable\": \"myresource\"\n \"args\": [\n \"config\",\n \"set\",\n \"--what-if\",\n { \"jsonInputArg\": \"--properties\" }\n ]\n}\n```\n\nDSC invokes the command for the resource as:\n\n```bash\nmyresource config set --what-if --properties \n```\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#args\n" + }, + "input": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/inputKind.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines how DSC should pass input to the command, either as environment variables or JSON\nover `stdin`. This property is optional when you define an object in the `args` list. If\nyou define a JSON input argument and an `input`, DSC sends the JSON data both ways:\n\n- If you define `input` as `env` and a JSON input argument, DSC sets an environment variable\n for each property in the JSON input and passes the JSON input object as a string to the\n defined argument.\n- If you define `input` as `stdin` and a JSON input argument, DSC passes the JSON input over\n stdin and as a string to the defined argument.\n- If you define a JSON input argument without defining the `input` property, DSC only passes\n the JSON input as a string to the defined argument.\n\nIf you don't define the `input` property and don't define a JSON input argument, DSC can't\npass the input JSON to the resource. This makes the manifest invalid. You must define the\n`input` property, a JSON input argument in the `args` property array, or both.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#input\n" + }, + "implementsPretest": { + "title": "Resource Performs Pre-Test", + "description": "Defines whether the DSC Resource performs its own test to ensure idempotency when calling the `set --what-if` command. Set this value to `true` if the DSC Resource tests input before processing how it will modify system state.", + "type": "boolean", + "default": false, + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines whether the DSC Resource performs its own test to ensure idempotency when calling the\n`set --what-if` command . Set this value to `true` if the DSC Resource tests input before\nprocessing how it will modify system state.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#implementspretest\n" + }, + "handlesExist": { + "title": "Resource handles _exist property", + "description": "Defines whether the DSC Resource has its own built-in handling for the `_exist` common property. Set this value to `true` if the DSC Resource handles instance deletion internally when receiving a `set --what-if` command where the instance defines the `_exist` property as `false`.", + "type": "boolean", + "default": false, + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines whether the DSC Resource has its own built-in handling for the [`_exist`][02] common\nproperty. Set this value to `true` if the DSC Resource handles instance deletion internally\nwhen receiving a `set --what-if` command where the instance defines the `_exist` property as\n`false`.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#handlesExist\n[02]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/properties/exist?view=dsc-3.0&preserve-view=true\n" + }, + "return": { + "description": "Defines whether the command returns a JSON blob of the DSC Resource's expected state after a set operation in what-if mode or the state and an array of the properties the DSC Resource would modify.", + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/returnKind.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines whether the command returns a JSON blob of the DSC Resource's expected state after a\nset operation in what-if mode or the state and an array of the properties the DSC Resource\nwould modify.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#return\n", + "markdownEnumDescriptions": [ + "_Final state only_\n\n> Indicates that the resource returns only the instance's expected final state after the\n> set operation as a JSON blob.\n", + "_Final state and changed properties_\n\n> Indicates that the resource returns the instance's expected final state and an array of\n> property names that the resource would modify.\n" + ] + } + }, + "oneOf": [ + { + "required": [ + "input" + ], + "not": { + "properties": { + "args": { + "contains": { + "type": "object" + } + } + } + } + }, + { + "not": { + "required": [ + "input" + ] + }, + "properties": { + "args": { + "errorMessage": "The `whatIf` command doesn't define either the `input` property or a JSON input argument, or it defines more than one JSON input argument. If you don't define the `input` property and don't define a JSON input argument, DSC can't pass the input JSON to the resource. You can only define one JSON input argument for a command.\n\nYou must define the `input` property, one JSON input argument in the `args` property array, or both. For more information, see:\n\nhttps://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true", + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + }, + { + "required": [ + "input" + ], + "properties": { + "args": { + "errorMessage": "You can only specify one JSON input argument for the `whatIf` command. Remove the extra JSON input argument. When you use the JSON input argument, DSC sends the full JSON object as a string to the named argument.\n\nFor more information, see:\n\nhttps://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true", + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + } + ], + "defaultSnippets": [ + { + "label": " Define without arguments", + "markdownDescription": "Define the `whatIf` command for the resource when no arguments are required and the JSON\ninput is sent over stdin or as environment variables.\n", + "body": { + "input": "${1|stdin,env|}", + "implementsPretest": "^${2|true,false|}", + "return": "${3|state,stateAndDiff|}", + "executable": "${4:executable_name}" + } + }, + { + "label": " Define with string arguments", + "markdownDescription": "Define the `whatIf` command for the resource when at least one argument is required and the\nJSON input is sent over stdin or as environment variables.", + "body": { + "input": "${1|stdin,env|}", + "implementsPretest": "^${2|true,false|}", + "return": "${3|state,stateAndDiff|}", + "executable": "${4:executable_name}", + "args": [ + "${5:--first-argument}" + ] + } + }, + { + "label": " Define with a JSON input argument", + "markdownDescription": "Define the `whatIf` command for the resource where the JSON input is passed as a one-line\nJSON object string to the specified argument.", + "body": { + "implementsPretest": "^${1|true,false|}", + "return": "${2|state,stateAndDiff|}", + "executable": "${3:executable_name}", + "args": [ + { + "jsonInputArg": "${4:argument_name}", + "mandatory": "^$5" + } + ] + } + } + ] + }, "manifest.test.json": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json", diff --git a/schemas/2024/04/bundled/resource/manifest.json b/schemas/2024/04/bundled/resource/manifest.json index 3ee9da2ce..6c3d3eb15 100644 --- a/schemas/2024/04/bundled/resource/manifest.json +++ b/schemas/2024/04/bundled/resource/manifest.json @@ -59,6 +59,9 @@ "set": { "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.set.json" }, + "whatIf": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json" + }, "test": { "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json" }, @@ -330,6 +333,89 @@ } ] }, + "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json", + "title": "What-if method", + "description": "Defines how DSC must call the DSC Resource to indicate whether and how the set command will modify an instance and how to process the output from the DSC Resource.", + "type": "object", + "required": [ + "executable" + ], + "properties": { + "executable": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/commandExecutable.json" + }, + "args": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/commandArgs.json" + }, + "input": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/inputKind.json" + }, + "implementsPretest": { + "title": "Resource Performs Pre-Test", + "description": "Defines whether the DSC Resource performs its own test to ensure idempotency when calling the `set --what-if` command. Set this value to `true` if the DSC Resource tests input before processing how it will modify system state.", + "type": "boolean", + "default": false + }, + "handlesExist": { + "title": "Resource handles _exist property", + "description": "Defines whether the DSC Resource has its own built-in handling for the `_exist` common property. Set this value to `true` if the DSC Resource handles instance deletion internally when receiving a `set --what-if` command where the instance defines the `_exist` property as `false`.", + "type": "boolean", + "default": false + }, + "return": { + "description": "Defines whether the command returns a JSON blob of the DSC Resource's expected state after a set operation in what-if mode or the state and an array of the properties the DSC Resource would modify.", + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/returnKind.json" + } + }, + "oneOf": [ + { + "required": [ + "input" + ], + "not": { + "properties": { + "args": { + "contains": { + "type": "object" + } + } + } + } + }, + { + "not": { + "required": [ + "input" + ] + }, + "properties": { + "args": { + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + }, + { + "required": [ + "input" + ], + "properties": { + "args": { + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + } + ] + }, "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json", diff --git a/schemas/2024/04/bundled/resource/manifest.vscode.json b/schemas/2024/04/bundled/resource/manifest.vscode.json index 429d5445a..ccdc82dc0 100644 --- a/schemas/2024/04/bundled/resource/manifest.vscode.json +++ b/schemas/2024/04/bundled/resource/manifest.vscode.json @@ -297,6 +297,9 @@ "set": { "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/resource/manifest.set.json" }, + "whatIf": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json" + }, "test": { "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json" }, @@ -784,6 +787,142 @@ } ] }, + "manifest.whatIf.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json", + "title": "What-if method", + "description": "Defines how DSC must call the DSC Resource to indicate whether and how the set command will modify an instance and how to process the output from the DSC Resource.", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines how DSC must call the DSC Resource to indicate whether and how the set command will\nmodify an instance and how to process the output from the DSC Resource. If a resource doesn't\ndefine this method in the manifest, DSC synthesizes this behavior by converting the result of\nthe test operation for the resource into the [set result][02].\n\nThis method definition has the same structure as the [set method][03] in the resource manifest.\n\nDSC sends data to the command in three ways:\n\n1. When `input` is `stdin`, DSC sends the data as a string representing the data as a compressed\n JSON object without spaces or newlines between the object properties.\n1. When `input` is `env`, DSC sends the data as environment variables. It creates an environment\n variable for each property in the input data object, using the name and value of the property.\n1. When the `args` array includes a JSON input argument definition, DSC sends the data as a string\n representing the data as a compressed JSON object to the specified argument.\n\nIf you don't define the `input` property and don't define a JSON input argument, DSC can't pass\nthe input JSON to the resource. You can only define one JSON input argument for a command.\n\nYou must define the `input` property, one JSON input argument in the `args` property array, or\nboth.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true\n[02]: https://learn.microsoft.com/powershell/dsc/reference/schemas/outputs/resource/set?view=dsc-3.0&preserve-view=true\n[03]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/set?view=dsc-3.0&preserve-view=true\n", + "type": "object", + "required": [ + "executable" + ], + "properties": { + "executable": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/commandExecutable.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines the name of the command to run. The value must be the name of a command discoverable\nin the system's `PATH` environment variable or the full path to the command. A file extension\nis only required when the command isn't recognizable by the operating system as an\nexecutable.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#executable\n" + }, + "args": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/commandArgs.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines an array of strings to pass as arguments to the command. DSC passes the arguments to\nthe command in the order they're specified.\n\nFor example, the given the following definition:\n\n```json\n{\n \"executable\": \"myresource\",\n \"args\": [\"config\", \"set\", \"--what-if\"],\n}\n```\n\nDSC invokes the command for the resource as:\n\n```bash\nmyresource config set --what-if\n```\n\nIf you want to pass the JSON object representing the property bag for a resource instance to\nan argument, you can define a single item in the array as a JSON object. Indicate the name of\nthe argument with the `jsonInputArg` string property and whether the argument is mandatory\nfor the command with the `mandatory` boolean property.` When the `mandatory` property is\ndefined as `true`, DSC passes an empty string to the argument when no JSON input is\navailable. When the `mandatory` property is undefined or defined as `false`, DSC doesn't pass\nthe argument at all when no JSON input is available. The default value for the `mandatory`\nproperty is `false`.\n\nFor example, given the following definition:\n\n```json\n{\n \"executable\": \"myresource\"\n \"args\": [\n \"config\",\n \"set\",\n \"--what-if\",\n { \"jsonInputArg\": \"--properties\" }\n ]\n}\n```\n\nDSC invokes the command for the resource as:\n\n```bash\nmyresource config set --what-if --properties \n```\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#args\n" + }, + "input": { + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/inputKind.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines how DSC should pass input to the command, either as environment variables or JSON\nover `stdin`. This property is optional when you define an object in the `args` list. If\nyou define a JSON input argument and an `input`, DSC sends the JSON data both ways:\n\n- If you define `input` as `env` and a JSON input argument, DSC sets an environment variable\n for each property in the JSON input and passes the JSON input object as a string to the\n defined argument.\n- If you define `input` as `stdin` and a JSON input argument, DSC passes the JSON input over\n stdin and as a string to the defined argument.\n- If you define a JSON input argument without defining the `input` property, DSC only passes\n the JSON input as a string to the defined argument.\n\nIf you don't define the `input` property and don't define a JSON input argument, DSC can't\npass the input JSON to the resource. This makes the manifest invalid. You must define the\n`input` property, a JSON input argument in the `args` property array, or both.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#input\n" + }, + "implementsPretest": { + "title": "Resource Performs Pre-Test", + "description": "Defines whether the DSC Resource performs its own test to ensure idempotency when calling the `set --what-if` command. Set this value to `true` if the DSC Resource tests input before processing how it will modify system state.", + "type": "boolean", + "default": false, + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines whether the DSC Resource performs its own test to ensure idempotency when calling the\n`set --what-if` command . Set this value to `true` if the DSC Resource tests input before\nprocessing how it will modify system state.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#implementspretest\n" + }, + "handlesExist": { + "title": "Resource handles _exist property", + "description": "Defines whether the DSC Resource has its own built-in handling for the `_exist` common property. Set this value to `true` if the DSC Resource handles instance deletion internally when receiving a `set --what-if` command where the instance defines the `_exist` property as `false`.", + "type": "boolean", + "default": false, + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines whether the DSC Resource has its own built-in handling for the [`_exist`][02] common\nproperty. Set this value to `true` if the DSC Resource handles instance deletion internally\nwhen receiving a `set --what-if` command where the instance defines the `_exist` property as\n`false`.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#handlesExist\n[02]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/properties/exist?view=dsc-3.0&preserve-view=true\n" + }, + "return": { + "description": "Defines whether the command returns a JSON blob of the DSC Resource's expected state after a set operation in what-if mode or the state and an array of the properties the DSC Resource would modify.", + "$ref": "#/$defs/PowerShell/DSC/main/schemas/2024/04/definitions/returnKind.json", + "markdownDescription": "***\n[_Online Documentation_][01]\n***\n\nDefines whether the command returns a JSON blob of the DSC Resource's expected state after a\nset operation in what-if mode or the state and an array of the properties the DSC Resource\nwould modify.\n\n[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true#return\n", + "markdownEnumDescriptions": [ + "_Final state only_\n\n> Indicates that the resource returns only the instance's expected final state after the\n> set operation as a JSON blob.\n", + "_Final state and changed properties_\n\n> Indicates that the resource returns the instance's expected final state and an array of\n> property names that the resource would modify.\n" + ] + } + }, + "oneOf": [ + { + "required": [ + "input" + ], + "not": { + "properties": { + "args": { + "contains": { + "type": "object" + } + } + } + } + }, + { + "not": { + "required": [ + "input" + ] + }, + "properties": { + "args": { + "errorMessage": "The `whatIf` command doesn't define either the `input` property or a JSON input argument, or it defines more than one JSON input argument. If you don't define the `input` property and don't define a JSON input argument, DSC can't pass the input JSON to the resource. You can only define one JSON input argument for a command.\n\nYou must define the `input` property, one JSON input argument in the `args` property array, or both. For more information, see:\n\nhttps://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true", + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + }, + { + "required": [ + "input" + ], + "properties": { + "args": { + "errorMessage": "You can only specify one JSON input argument for the `whatIf` command. Remove the extra JSON input argument. When you use the JSON input argument, DSC sends the full JSON object as a string to the named argument.\n\nFor more information, see:\n\nhttps://learn.microsoft.com/powershell/dsc/reference/schemas/resource/manifest/whatif?view=dsc-3.0&preserve-view=true", + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + } + ], + "defaultSnippets": [ + { + "label": " Define without arguments", + "markdownDescription": "Define the `whatIf` command for the resource when no arguments are required and the JSON\ninput is sent over stdin or as environment variables.\n", + "body": { + "input": "${1|stdin,env|}", + "implementsPretest": "^${2|true,false|}", + "return": "${3|state,stateAndDiff|}", + "executable": "${4:executable_name}" + } + }, + { + "label": " Define with string arguments", + "markdownDescription": "Define the `whatIf` command for the resource when at least one argument is required and the\nJSON input is sent over stdin or as environment variables.", + "body": { + "input": "${1|stdin,env|}", + "implementsPretest": "^${2|true,false|}", + "return": "${3|state,stateAndDiff|}", + "executable": "${4:executable_name}", + "args": [ + "${5:--first-argument}" + ] + } + }, + { + "label": " Define with a JSON input argument", + "markdownDescription": "Define the `whatIf` command for the resource where the JSON input is passed as a one-line\nJSON object string to the specified argument.", + "body": { + "implementsPretest": "^${1|true,false|}", + "return": "${2|state,stateAndDiff|}", + "executable": "${3:executable_name}", + "args": [ + { + "jsonInputArg": "${4:argument_name}", + "mandatory": "^$5" + } + ] + } + } + ] + }, "manifest.test.json": { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json", diff --git a/schemas/2024/04/outputs/resource/list.json b/schemas/2024/04/outputs/resource/list.json index e9f63bbdd..80fe5a84b 100644 --- a/schemas/2024/04/outputs/resource/list.json +++ b/schemas/2024/04/outputs/resource/list.json @@ -24,6 +24,7 @@ "Get", "Set", "SetHandlesExist", + "WhatIf", "Test", "Delete", "Export", diff --git a/schemas/2024/04/resource/manifest.json b/schemas/2024/04/resource/manifest.json index ddfd2cee2..0cafa7473 100644 --- a/schemas/2024/04/resource/manifest.json +++ b/schemas/2024/04/resource/manifest.json @@ -59,6 +59,9 @@ "set": { "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.set.json" }, + "whatIf": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json" + }, "test": { "$ref": "/PowerShell/DSC/main/schemas/2024/04/resource/manifest.test.json" }, diff --git a/schemas/2024/04/resource/manifest.whatIf.json b/schemas/2024/04/resource/manifest.whatIf.json new file mode 100644 index 000000000..ef34720e9 --- /dev/null +++ b/schemas/2024/04/resource/manifest.whatIf.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/resource/manifest.whatIf.json", + "title": "What-if method", + "description": "Defines how DSC must call the DSC Resource to indicate whether and how the set command will modify an instance and how to process the output from the DSC Resource.", + "type": "object", + "required": [ + "executable" + ], + "properties": { + "executable": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/commandExecutable.json" + }, + "args": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/commandArgs.json" + }, + "input": { + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/inputKind.json" + }, + "implementsPretest": { + "title": "Resource Performs Pre-Test", + "description": "Defines whether the DSC Resource performs its own test to ensure idempotency when calling the `set --what-if` command. Set this value to `true` if the DSC Resource tests input before processing how it will modify system state.", + "type": "boolean", + "default": false + }, + "handlesExist": { + "title": "Resource handles _exist property", + "description": "Defines whether the DSC Resource has its own built-in handling for the `_exist` common property. Set this value to `true` if the DSC Resource handles instance deletion internally when receiving a `set --what-if` command where the instance defines the `_exist` property as `false`.", + "type": "boolean", + "default": false + }, + "return": { + "description": "Defines whether the command returns a JSON blob of the DSC Resource's expected state after a set operation in what-if mode or the state and an array of the properties the DSC Resource would modify.", + "$ref": "/PowerShell/DSC/main/schemas/2024/04/definitions/returnKind.json" + } + }, + "oneOf": [ + { + "required": [ + "input" + ], + "not": { + "properties": { + "args": { + "contains": { + "type": "object" + } + } + } + } + }, + { + "not": { + "required": [ + "input" + ] + }, + "properties": { + "args": { + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + }, + { + "required": [ + "input" + ], + "properties": { + "args": { + "contains": { + "type": "object" + }, + "minContains": 1, + "maxContains": 1 + } + } + } + ] +} diff --git a/schemas/src/outputs/resource/list.yaml b/schemas/src/outputs/resource/list.yaml index ac7e558a9..0eda2c42c 100644 --- a/schemas/src/outputs/resource/list.yaml +++ b/schemas/src/outputs/resource/list.yaml @@ -34,6 +34,7 @@ properties: - Get - Set - SetHandlesExist + - WhatIf - Test - Delete - Export diff --git a/schemas/src/resource/manifest.whatIf.yaml b/schemas/src/resource/manifest.whatIf.yaml new file mode 100644 index 000000000..711c86024 --- /dev/null +++ b/schemas/src/resource/manifest.whatIf.yaml @@ -0,0 +1,280 @@ +# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema +$schema: https://json-schema.org/draft/2020-12/schema +$id: ///resource/manifest.whatIf.yaml + +title: What-if method +description: >- + Defines how DSC must call the DSC Resource to indicate whether and how the set command will + modify an instance and how to process the output from the DSC Resource. +markdownDescription: | # VS Code only + *** + [_Online Documentation_][01] + *** + + Defines how DSC must call the DSC Resource to indicate whether and how the set command will + modify an instance and how to process the output from the DSC Resource. If a resource doesn't + define this method in the manifest, DSC synthesizes this behavior by converting the result of + the test operation for the resource into the [set result][02]. + + This method definition has the same structure as the [set method][03] in the resource manifest. + + DSC sends data to the command in three ways: + + 1. When `input` is `stdin`, DSC sends the data as a string representing the data as a compressed + JSON object without spaces or newlines between the object properties. + 1. When `input` is `env`, DSC sends the data as environment variables. It creates an environment + variable for each property in the input data object, using the name and value of the property. + 1. When the `args` array includes a JSON input argument definition, DSC sends the data as a string + representing the data as a compressed JSON object to the specified argument. + + If you don't define the `input` property and don't define a JSON input argument, DSC can't pass + the input JSON to the resource. You can only define one JSON input argument for a command. + + You must define the `input` property, one JSON input argument in the `args` property array, or + both. + + [01]: /reference/schemas/resource/manifest/whatif? + [02]: /reference/schemas/outputs/resource/set? + [03]: /reference/schemas/resource/manifest/set? + +type: object +required: + - executable +properties: + executable: + $ref: ///definitions/commandExecutable.yaml + markdownDescription: | + *** + [_Online Documentation_][01] + *** + + Defines the name of the command to run. The value must be the name of a command discoverable + in the system's `PATH` environment variable or the full path to the command. A file extension + is only required when the command isn't recognizable by the operating system as an + executable. + + [01]: /reference/schemas/resource/manifest/whatif?#executable + args: + $ref: ///definitions/commandArgs.yaml + markdownDescription: | + *** + [_Online Documentation_][01] + *** + + Defines an array of strings to pass as arguments to the command. DSC passes the arguments to + the command in the order they're specified. + + For example, the given the following definition: + + ```json + { + "executable": "myresource", + "args": ["config", "set", "--what-if"], + } + ``` + + DSC invokes the command for the resource as: + + ```bash + myresource config set --what-if + ``` + + If you want to pass the JSON object representing the property bag for a resource instance to + an argument, you can define a single item in the array as a JSON object. Indicate the name of + the argument with the `jsonInputArg` string property and whether the argument is mandatory + for the command with the `mandatory` boolean property.` When the `mandatory` property is + defined as `true`, DSC passes an empty string to the argument when no JSON input is + available. When the `mandatory` property is undefined or defined as `false`, DSC doesn't pass + the argument at all when no JSON input is available. The default value for the `mandatory` + property is `false`. + + For example, given the following definition: + + ```json + { + "executable": "myresource" + "args": [ + "config", + "set", + "--what-if", + { "jsonInputArg": "--properties" } + ] + } + ``` + + DSC invokes the command for the resource as: + + ```bash + myresource config set --what-if --properties + ``` + + [01]: /reference/schemas/resource/manifest/whatif?#args + input: + $ref: ///definitions/inputKind.yaml + markdownDescription: | + *** + [_Online Documentation_][01] + *** + + Defines how DSC should pass input to the command, either as environment variables or JSON + over `stdin`. This property is optional when you define an object in the `args` list. If + you define a JSON input argument and an `input`, DSC sends the JSON data both ways: + + - If you define `input` as `env` and a JSON input argument, DSC sets an environment variable + for each property in the JSON input and passes the JSON input object as a string to the + defined argument. + - If you define `input` as `stdin` and a JSON input argument, DSC passes the JSON input over + stdin and as a string to the defined argument. + - If you define a JSON input argument without defining the `input` property, DSC only passes + the JSON input as a string to the defined argument. + + If you don't define the `input` property and don't define a JSON input argument, DSC can't + pass the input JSON to the resource. This makes the manifest invalid. You must define the + `input` property, a JSON input argument in the `args` property array, or both. + + [01]: /reference/schemas/resource/manifest/whatif?#input + implementsPretest: + title: Resource Performs Pre-Test + description: >- + Defines whether the DSC Resource performs its own test to ensure idempotency when calling the + `set --what-if` command. Set this value to `true` if the DSC Resource tests input before + processing how it will modify system state. + type: boolean + default: false + # VS Code only + markdownDescription: | + *** + [_Online Documentation_][01] + *** + + Defines whether the DSC Resource performs its own test to ensure idempotency when calling the + `set --what-if` command . Set this value to `true` if the DSC Resource tests input before + processing how it will modify system state. + + [01]: /reference/schemas/resource/manifest/whatif?#implementspretest + handlesExist: + title: Resource handles _exist property + description: >- + Defines whether the DSC Resource has its own built-in handling for the `_exist` common + property. Set this value to `true` if the DSC Resource handles instance deletion internally + when receiving a `set --what-if` command where the instance defines the `_exist` property as + `false`. + type: boolean + default: false + # VS Code only + markdownDescription: | + *** + [_Online Documentation_][01] + *** + + Defines whether the DSC Resource has its own built-in handling for the [`_exist`][02] common + property. Set this value to `true` if the DSC Resource handles instance deletion internally + when receiving a `set --what-if` command where the instance defines the `_exist` property as + `false`. + + [01]: /reference/schemas/resource/manifest/whatif?#handlesExist + [02]: /reference/schemas/resource/properties/exist? + return: + description: >- + Defines whether the command returns a JSON blob of the DSC Resource's expected state after a + set operation in what-if mode or the state and an array of the properties the DSC Resource + would modify. + $ref: ///definitions/returnKind.yaml + # VS Code only + markdownDescription: | + *** + [_Online Documentation_][01] + *** + + Defines whether the command returns a JSON blob of the DSC Resource's expected state after a + set operation in what-if mode or the state and an array of the properties the DSC Resource + would modify. + + [01]: /reference/schemas/resource/manifest/whatif?#return + markdownEnumDescriptions: + - | # state + _Final state only_ + + > Indicates that the resource returns only the instance's expected final state after the + > set operation as a JSON blob. + - | # stateAndDiff + _Final state and changed properties_ + + > Indicates that the resource returns the instance's expected final state and an array of + > property names that the resource would modify. + +# Need to use a oneOf with three possibilities because YAML extension in VS Code doesn't understand +# minContains - so we can't use a single if/else/then. Note that JSON, but not YAML, will fail when +# the manifest defines more than one JSON input argument. If/when the YAML extension is updated to +# support 2019-09 and later, we can simplify this to two schemas. +# +# We use long lines for error messages, which can't use Markdown. +oneOf: + - # What-if command with explicit input kind - when `input` is defined and `args` is only strings. + # This subschema never triggers an error in testing. + required: [input] + not: + properties: { args: { contains: { type: object } } } + - # What-if command with JSON input argument - when `input` isn't defined and `args` doesn't + # include a JSON input argument. Only raises an error when `args` has zero JSON input arguments + # or more than one. + not: { required: [input] } + properties: + args: + errorMessage: |- + The `whatIf` command doesn't define either the `input` property or a JSON input argument, or it defines more than one JSON input argument. If you don't define the `input` property and don't define a JSON input argument, DSC can't pass the input JSON to the resource. You can only define one JSON input argument for a command. + + You must define the `input` property, one JSON input argument in the `args` property array, or both. For more information, see: + + /reference/schemas/resource/manifest/whatif? + contains: { type: object } + minContains: 1 + maxContains: 1 + - # What-if command with explicit input kind and JSON input argument - when `input` is defined and + # args includes a JSON input argument. Only raises an error when `input` is defined and `args` + # contains more than one JSON input argument. + required: [input] + properties: + args: + errorMessage: |- + You can only specify one JSON input argument for the `whatIf` command. Remove the extra JSON input argument. When you use the JSON input argument, DSC sends the full JSON object as a string to the named argument. + + For more information, see: + + /reference/schemas/resource/manifest/whatif? + contains: { type: object } + minContains: 1 + maxContains: 1 + +defaultSnippets: # VS Code only + - label: ' Define without arguments' + markdownDescription: | + Define the `whatIf` command for the resource when no arguments are required and the JSON + input is sent over stdin or as environment variables. + body: + input: ${1|stdin,env|} + implementsPretest: ^${2|true,false|} + return: ${3|state,stateAndDiff|} + executable: ${4:executable_name} + - label: ' Define with string arguments' + markdownDescription: |- + Define the `whatIf` command for the resource when at least one argument is required and the + JSON input is sent over stdin or as environment variables. + body: + input: ${1|stdin,env|} + implementsPretest: ^${2|true,false|} + return: ${3|state,stateAndDiff|} + executable: ${4:executable_name} + args: + - ${5:--first-argument} + - label: ' Define with a JSON input argument' + markdownDescription: |- + Define the `whatIf` command for the resource where the JSON input is passed as a one-line + JSON object string to the specified argument. + body: + implementsPretest: ^${1|true,false|} + return: ${2|state,stateAndDiff|} + executable: ${3:executable_name} + args: + - jsonInputArg: ${4:argument_name} + mandatory: ^$5 diff --git a/schemas/src/resource/manifest.yaml b/schemas/src/resource/manifest.yaml index 11899107f..81e265ed7 100644 --- a/schemas/src/resource/manifest.yaml +++ b/schemas/src/resource/manifest.yaml @@ -445,6 +445,8 @@ properties: $ref: ///resource/manifest.get.yaml set: $ref: ///resource/manifest.set.yaml + whatIf: + $ref: ///resource/manifest.whatIf.yaml test: $ref: ///resource/manifest.test.yaml delete: