From fea6566a60d5c914a93e1b5325b5b311e3a79563 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Tue, 5 Aug 2025 15:01:11 -0500 Subject: [PATCH] (DOCS) Draft resource design docs This change adds conceptual documentation as the initial offering for a resource _design_ guide. It is intended to convey high-level implementation-agnostic guidance for defining DSC resources, including resource manifests and instance schemas. The guide doesn't cover any specifics for defining commands or the resource in a particular language. Those concerns are better covered in the resource development kits or the sample resource tutorials, not the conceptual guide. --- docs/.markdownlint-cli2.yaml | 33 ++ docs/.markdownlint.yaml | 117 +++++++ .../resources/authoring/emitting-messages.md | 326 ++++++++++++++++++ .../resources/authoring/exit-codes.md | 182 ++++++++++ .../authoring/exporter/resource-manifest.md | 42 +++ docs/concepts/resources/authoring/index.md | 64 ++++ .../resources/authoring/manifest-metadata.md | 128 +++++++ .../authoring/operation-invocations.md | 259 ++++++++++++++ docs/concepts/resources/authoring/toc.yml | 21 ++ .../typical/resource-instance-schema.md | 50 +++ .../authoring/typical/resource-manifest.md | 72 ++++ 11 files changed, 1294 insertions(+) create mode 100644 docs/.markdownlint-cli2.yaml create mode 100644 docs/.markdownlint.yaml create mode 100644 docs/concepts/resources/authoring/emitting-messages.md create mode 100644 docs/concepts/resources/authoring/exit-codes.md create mode 100644 docs/concepts/resources/authoring/exporter/resource-manifest.md create mode 100644 docs/concepts/resources/authoring/index.md create mode 100644 docs/concepts/resources/authoring/manifest-metadata.md create mode 100644 docs/concepts/resources/authoring/operation-invocations.md create mode 100644 docs/concepts/resources/authoring/toc.yml create mode 100644 docs/concepts/resources/authoring/typical/resource-instance-schema.md create mode 100644 docs/concepts/resources/authoring/typical/resource-manifest.md diff --git a/docs/.markdownlint-cli2.yaml b/docs/.markdownlint-cli2.yaml new file mode 100644 index 00000000..eb7f2ac9 --- /dev/null +++ b/docs/.markdownlint-cli2.yaml @@ -0,0 +1,33 @@ +# Rule definitions live in .markdownlint.json + +# Include a custom rule package +# customRules: +# - markdownlint-rule-titlecase + +# Fix any fixable errors +fix: true + +# Define a custom front matter pattern +# frontMatter: (^---\s*$[^]*?^---\s*$)(\r\n|\r|\n|$) + +# Define glob expressions to use (only valid at root) +# globs: +# - "!*bout.md" + +# Define glob expressions to ignore +# ignores: +# - breadcrumb + +# Use a plugin to recognize math +# markdownItPlugins: +# - - "@iktakahiro/markdown-it-katex" + +# Disable inline config comments +noInlineConfig: false + +# Disable progress on stdout (only valid at root) +noProgress: true + +# Use a specific formatter (only valid at root) +# outputFormatters: +# - [markdownlint-cli2-formatter-default] diff --git a/docs/.markdownlint.yaml b/docs/.markdownlint.yaml new file mode 100644 index 00000000..88144429 --- /dev/null +++ b/docs/.markdownlint.yaml @@ -0,0 +1,117 @@ +# docsmd.alert: true +# docsmd.codesnippet: true +# docsmd.column: true +# docsmd.image: true +# docsmd.moniker: true +# docsmd.no-loc: true +# docsmd.row: true +# docsmd.securelinks: true +# docsmd.syntax: true +# docsmd.video: true +# docsmd.xref: true +# docsmd.zone: true + +MD001: true # header-increment +# MD002 # first-header-h1 - Superceded by MD041 +MD003: # header-style + style: atx +MD004: # ul-style + style: dash +MD005: true # list-indent +# MD006 # ul-start-left - Superceded by MD007's start_indented option +MD007: # ul-indent + indent: 2 + start_indented: false +# MD008 # Removed from linter; used to specify indentation for ul +MD009: # no-trailing-spaces + br_spaces: 2 + strict: true +MD010: true # no-hard-tabs +MD011: true # no-reversed-links +MD012: true # no-multiple-blanks +MD013: # line-length + code_block_line_length: 90 + code_blocks: true + heading_line_length: 100 + headings: true + line_length: 100 + stern: true + tables: false +MD014: true # commands-show-output +# MD015 # "Use of non-atx style headers" - Removed from linter, replaced by MD003 +# MD016 # "Use of non-closed-atx style headers" - Removed from linter, replaced by MD003 +# MD017 # "Use of non-setext style headers" - Removed from linter, replaced by MD003 +MD018: true # no-missing-space-atx +MD019: true # no-multiple-space-atx +MD020: true # no-missing-space-closed-atx +MD021: true # no-multiple-space-closed-atx +MD022: true # blanks-around-headers +MD023: true # header-start-left +MD024: # no-duplicate-header + siblings_only: true +MD025: # single-h1 + front_matter_title: '' + level: 1 +MD026: # no-trailing-punctuation + punctuation: '.,;:!。,;:!?' +MD027: true # no-multiple-space-blockquote +MD028: true # no-blanks-blockquote +MD029: # ol-prefix + style: one +MD030: true # list-marker-space +MD031: true # blanks-around-fences +MD032: true # blanks-around-lists +MD033: # no-inline-html + allowed_elements: + - a + - br + - code + - kbd + - li + - properties + - sup + - tags + - ul +MD034: true # no-bare-urls +MD035: # hr-style + style: '---' +MD036: true # no-emphasis-as-header +MD037: true # no-space-in-emphasis +MD038: true # no-space-in-code +MD039: true # no-space-in-links +MD040: false # fenced-code-language +MD041: # first-line-h1 + front_matter_title: '' +MD042: true # no-empty-links +MD043: false # required-headers +MD044: # proper-names + code_blocks: false + names: + - PowerShell + - IntelliSense + - Authenticode + - CentOS + - Contoso + - CoreOS + - Debian + - Ubuntu + - openSUSE + - RHEL + - JavaScript + - .NET + - NuGet + - VS Code + - Newtonsoft +MD045: true # no-alt-text +MD046: # code-block-style + style: fenced +MD047: true # single-trailing-newline +MD048: # code-fence-style + style: backtick +MD049: # emphasis-style + style: underscore +MD050: # strong-style + style: asterisk +MD051: true # link-fragments +MD052: true # reference-links-images +MD053: true # link-image-reference-definitions diff --git a/docs/concepts/resources/authoring/emitting-messages.md b/docs/concepts/resources/authoring/emitting-messages.md new file mode 100644 index 00000000..2ac92674 --- /dev/null +++ b/docs/concepts/resources/authoring/emitting-messages.md @@ -0,0 +1,326 @@ +--- +description: >- + Considerations and guidance for emitting messages from a DSC resource. +ms.date: 08/15/2025 +title: Emitting messages from a DSC resource +--- + +# Emitting messages from a DSC resource + +DSC uses a messaging system to provide runtime information to users. By default, DSC emits messages +as strings to stderr with ANSI console coloring for the timestamp, message level, and line number. +You can use the [--trace-format](../../../reference/cli/index.md#--trace-format) option to have DSC +emit the messages to stderr without console coloring or as JSON Lines. + +DSC supports consuming and surfacing messages from resources to provide context and helpful +information to users. + +This document provides an overview of the messaging system and guidance for how a resource should +integrate with DSC to emit useful messages. + +## DSC message levels + +Messages in DSC are categorized by their level. The following list shows the valid message levels +from highest to lowest level. + +- `error` - messages at this level indicate critical problems. +- `warn` (default) - messages at this level provide important information that may affect usage + and behavior. +- `info` - messages at this level provide useful but less important information about operational + behavior. +- `debug` - messages at this level surface verbose information primarily useful for troubleshooting + and investigating. +- `trace` - messages at this level surface extremely verbose and low-level information for + troubleshooting and investigating. + +> [!WARNING] +> The `trace` level output emits all JSON input/output that DSC processes during execution. DSC +> doesn't sanitize the JSON before emitting it. This trace level is only intended for developer +> use. Never redirect `trace` level output to storage as it might contain sensitive information. + +Users can configure the trace level for DSC by specifying the +[--trace-level](../../../reference/cli/index.md#--trace-level) command option, setting the +[DSC_TRACE_LEVEL](../../../reference/cli/index.md#environment-variables) environmental variable, or +by modifying the settings for DSC. + +The trace level defines the minimum message type to emit when using DSC. Because the default trace +level is `warn`, DSC only emits error and warning messages by default. The following table shows +how the trace level determines which messages DSC emits: + +| Trace level | Emitted message levels | +|:-----------:|:------------------------------------------| +| `error` | `error` | +| `warn` | `error`, `warn` | +| `info` | `error`, `warn`, `info` | +| `debug` | `error`, `warn`, `info`, `debug` | +| `trace` | `error`, `warn`, `info`, `debug`, `trace` | + +## DSC message output + +By default, DSC emits trace messages to stderr with ANSI console coloring. + +When a user specifies the [--trace-format](../../../reference/cli/index.md#--trace-format) option +as `plaintext`, DSC emits the messages in the same format but without console colors. + +When a user specifies the format as `json`, DSC emits each message as a JSON Line to stderr. + +When the [--trace-level](../../../reference/cli/index.md#--trace-level) option is set to `debug` or +`trace`, DSC includes additional information about where in _DSC's code_ the message was emitted. + +### Console message output + +When the trace level is set to `info`, `warn`, or `eror`, DSC emits messages from resources to +stderr with the following syntax: + +```Syntax + PID : +``` + +- `` is the ISO8601 timestamp for when DSC emitted the message from the resource. It + doesn't represent the timestamp for when the _resource emitted_ the message. +- `` is the all-caps representation of the messaging level: `ERROR`, `WARN`, `INFO`, + `DEBUG`, or `TRACE`. +- `` is the process ID for the process DSC spawned to invoke the resource. +- `` is the string value of the message emitted by the resource. + +For example: + +```console +2025-08-15T14:42:53.970726Z WARN PID 29072: Message from resource +``` + +When the trace level is set to `debug` or `trace`, DSC emits messages from resources to stderr with +the following syntax: + +```Syntax + : : PID : +``` + +- `` is the ISO8601 timestamp for when DSC emitted the message from the resource. It + doesn't represent the timestamp for when the _resource emitted_ the message. +- `` is the all-caps representation of the messaging level: `ERROR`, `WARN`, `INFO`, + `DEBUG`, or `TRACE`. +- `` indicates where in the DSC source code the message was emitted from, using + Rust module path syntax. +- `` indicates which line in the DSC source code the message was emitted from. +- `` is the process ID for the process DSC spawned to invoke the resource. +- `` is the string value of the message emitted by the resource. + +For example: + +```console +2025-08-15T14:57:02.218913Z WARN dsc_lib::dscresources::command_resource: 901: PID 34460: Message from resource +``` + +### JSON message output + +When the trace format is `json` and the trace level is set to `info`, `warn`, or `eror`, DSC emits +messages from resources to stderr as JSON Line objects with the following properties: + +- `timestamp` - the ISO8601 timestamp for when DSC emitted the message from the resource. It + doesn't represent the timestamp for when the _resource emitted_ the message. +- `level` - is the all-caps representation of the messaging level: `ERROR`, `WARN`, `INFO`, + `DEBUG`, or `TRACE`. +- `fields` - is an object with the `message` string subproperty containing the message from the + resource. The message is prefixed with `PID :` where `` is the process ID for the + process DSC spawned to invoke the resource. + +For example: + +```json +{ + "timestamp": "2025-08-18T19:47:43.376148Z", + "level": "WARN", + "fields": { + "message": "PID 1508: Message from resource" + } +} +``` + +When the trace format is `json` and the trace level is set to `debug` or `trace`, DSC emits +messages from resources to stderr as JSON Line objects with the following properties: + +- `timestamp` - the ISO8601 timestamp for when DSC emitted the message from the resource. It + doesn't represent the timestamp for when the _resource emitted_ the message. +- `level` - is the all-caps representation of the messaging level: `ERROR`, `WARN`, `INFO`, + `DEBUG`, or `TRACE`. +- `fields` - is an object with the `message` string subproperty containing the message from the + resource. The message is prefixed with `PID :` where `` is the process ID for the + process DSC spawned to invoke the resource. +- `target` - indicates where in the DSC source code the message was emitted from, using + Rust module path syntax. +- `line_number` - indicates which line in the DSC source code the message was emitted from. + +For example: + +```json +{ + "timestamp": "2025-08-18T20:37:55.100565Z", + "level": "WARN", + "fields": { + "message": "PID 16160: Message from resource" + }, + "target": "dsc_lib::dscresources::command_resource", + "line_number": 921 +} +``` + +## How DSC consumes messages from resources + +DSC processes lines of text emitted to stderr by a resource using the following procedure: + +1. If the emitted line is JSON, DSC deserializes it and checks whether it defines a level property: + + - If the object defines the `error` property, DSC emits an error-level message, using the value + of `error` as the message text. + - If the object defines the `warn` property, DSC emits a warning-level message, using the value + of `warn` as the message text. + - If the object defines the `info` property, DSC emits an info-level message, using the value of + `info` as the message text. + - If the object defines the `debug` property, DSC emits a debug-level message, using the value + of `debug` as the message text. + - If the object defines the `trace` property, DSC emits a trace-level message, using the value + of `trace` as the message text. + + If the object doesn't define any of the level properties, DSC emits a trace-level message, using + the emitted line as the message text without unwrapping the JSON. +1. If DSC can't parse the line as JSON, DSC emits a trace-level message, using the line as the + message text. + +DSC always prefixes the message text with the `PID :` prefix, where `` is the ID for the +process DSC spawned to invoke the resource. + +### Emitting structured data + +Currently, DSC only supports emitting string messages at the defined levels. DSC can't bubble up +additional structured data with the message due to limitations in the tracing library DSC uses. +Instead, to send structured data, use the following convention: + +1. Create a JSON object representing your data: + + ```json + { + "key1": true, + "key2": "key2 value" + } + ``` + +1. Convert the JSON to an escaped string representation of the data as compressed JSON: + + ```json + "{\"key1\":true,\"key2\":\"key2 value\"}" + ``` + +1. Emit a message with the appropriate level as a JSON Line: + + ```json + {"info":"{\"key1\":true,\"key2\":\"key2 value\"}"} + ``` + +This convention requires the caller to unwrap the emitted data from the trace that DSC emits. + +## Emitting error messages + +By default, DSC recognizes failures for resource operations by inspecting the exit code your +resource returns for an operation invocation. If your manifest defines useful +[exit codes](./exit-codes.md), DSC can provide a human-readable synopsis for why the operation +failed. + +Resources should emit error messages prior to returning a nonzero exit code to provide more +detailed information that a user can reference for troubleshooting. + +To emit a `error` level message from your resource, emit a JSON Line to stderr with a single +property, `error`, where the value is a string representing the message you want to emit. + +For example: + +```json +{"error":"Message contents"} +``` + +## Emitting warning messages + +Resources should emit warning messages to indicate non-critical issues and information about the +resource's behavior to the user. + +Consider emitting warning messages under the following guidelines: + +- Emit a warning message when your resource is aware of an important concern that won't cause the + execution of the current operation to fail but may affect other operations. +- Emit a warning message when your resource needs to inform a user about effects of an operation + that aren't obvious or expected by default. + +To emit a `warn` level message from your resource, emit a JSON Line to stderr with a single +property, `warn`, where the value is a string representing the message you want to emit. + +For example: + +```json +{"warn":"Message contents"} +``` + +## Emitting info messages + +Resources should emit info messages to provide non-critical information about the resource's +behavior to the user. + +Consider emitting info messages under the following guidelines: + +- Emit an info message when you want to surface context or information to a user about the behavior + of the resource. +- Don't emit info messages for low-level details about the internals of your resource. + +To emit a `info` level message from your resource, emit a JSON Line to stderr with a single +property, `info`, where the value is a string representing the message you want to emit. + +For example: + +```json +{"info":"Message contents"} +``` + +## Emitting debug messages + +Resources can emit debug messages to help users and integrating developers troubleshoot resource +behavior. + +Consider emitting debug messages under the following guidelines: + +- Emit a debug message when you want to provide context for troubleshooting the resource. +- Emit debug messages consistently. If you emit a debug message indicating the start of an internal + function or loop, also emit a debug message when that internal operation ends. + +To emit a `debug` level message from your resource, emit a JSON Line to stderr with a single +property, `debug`, where the value is a string representing the message you want to emit. + +For example: + +```json +{"debug":"Message contents"} +``` + +## Emitting trace messages + +Generally, resources shouldn't emit trace messages. If you need to provide more detailed +information than implied by debug messages, emit that information as trace messages. + +Consider emitting trace messages under the following guidelines: + +- Emit trace messages to provide extremely low-level information about the internal processing of + the resource. +- Emit trace messages for maintainers and integrating developers to use when investigating and + troubleshooting resource behavior. + +To emit a `trace` level message from your resource, emit a JSON Line to stderr with a single +property, `trace`, where the value is a string representing the message you want to emit. + +For example: + +```json +{"trace":"Message contents"} +``` + +## Related content + +- [Designing a DSC resource](./index.md) +- [Defining exit codes for a DSC resource](./exit-codes.md) diff --git a/docs/concepts/resources/authoring/exit-codes.md b/docs/concepts/resources/authoring/exit-codes.md new file mode 100644 index 00000000..5889b54c --- /dev/null +++ b/docs/concepts/resources/authoring/exit-codes.md @@ -0,0 +1,182 @@ +--- +description: >- + Considerations and guidance for defining exit codes for a resource. +ms.date: 08/15/2025 +title: Defining exit codes for a DSC resource +--- + +# Defining exit codes for a DSC resource + +DSC determines whether a resource operation executed successfully by checking the exit code for +the resource process: + +- DSC interprets exit code `0` as a successful operation. +- DSC interprets any nonzero exit code as a failed operation. + +Resources that don't define the `exitCodes` field in their manifest can only surface success or +failure to users. To provide a better user experience, you can define exit codes and their meaning +in the resource manifest. + +## How DSC uses exit codes + +When a resource returns a nonzero exit code for an operation, DSC marks the operation for that +resource as a failure and emits an error trace message indicating the failure to the user. + +The error message text uses the following syntax: + +```Syntax +Command: Resource '' [exit code ] manifest description: +``` + +The text wrapped in angle brackets (`<>`) indicates placeholders that DSC replaces with information +from the resource: + +- `` is the executable DSC called to invoke the operation for the resource, defined by + the `.executable` field in the manifest, like `get.executable`. +- `` is the exit code returned by the resource for the operation, like `1`. +- `` is the descriptive text for that exit code defined in the resource manifest. + +For example, given the following manifest snippet: + +```jsonc +{ + // Ellided manifest fields + "get": { + "executable": "example-resource" + }, + "exitCodes": { + "0": "success", + "1": "failure", + "70": "Invalid data" + } +} +``` + +If the resource returns exit code `70` for the `get` operation, DSC emits the following error +message: + +```console +Command: Resource 'example-resource' [exit code 70] manifest description: Invalid data +``` + +For more information about trace messaging in DSC and how a resource can participate in messaging, +see [Emitting messages from a DSC resource](./emitting-messages.md). + +## Minimal exit codes + +The smallest definition of semantic exit codes for a resource is to map `0` to success and `1` to +failure. The snippet below shows the minimal definition in a resource manifest: + +```json +{ + "exitCodes": { + "0": "success", + "1": "unknown failure", + } +} +``` + +However, this definition doesn't actually provide helpful context to a user - nonzero exit codes +_definitionally_ represent failures for DSC resources. + +The rest of this document provides guidance for defining useful resource exit codes. + +## Defining useful exit codes + +When you implement a resource, follow these guidelines: + +- Define exit code `0` to indicate a successful operation. +- Define exit code `1` to indicate an unknown or otherwise unhandled failure. +- Define an exit code for every fatal error you explicitly handle in your resource implementation. +- When defining exit codes for a resource that supports Linux or Unix, limit your exit codes to + using `0` through `255`. Consider only defining custom exit codes other than `0` and `1` in the + range `64` through `113`. + + For more information, see + ["Exit Status" in the GNU Bash Reference Manual](https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html) + and + ["Appendix E. Exit Codes With Special Meanings" in the Advanced Bash-Scripting Guide](https://tldp.org/LDP/abs/html/exitcodes.html). +- Use a coherent model for how you define your exit codes. For example, you might determine that + you want to use exit codes `10` through `19` for API-related failures and exit codes `20` + through `29` for validation errors. + + If you don't have enough failure causes to define a coherent model, add new exit codes by + incrementing the last-defined exit code by 1. If the last defined exit code was `4`, the next + exit code you define should be `5`. +- Avoid renumbering your exit codes as much as possible. Any users or integrating developers + relying on your exit codes will need to update their scripts or other integrations whenever you + change the semantics of an existing exit code. +- If your resource is wrapping an API or external command that returns exit codes, consider + defining your exit codes with the same numbers and ensure the description matches the underlying + API. +- Keep your exit code descriptions relatively short - no more than 80 characters. You should provide + additional context for users by + [emitting error messages](./emitting-messages.md#emitting-error-messages) from your resource + before exiting. + +## Examples + +The following examples show how you can define exit codes for a resource. + +### Example 1: Incrementing exit codes + +This example cross-platform resource starts by defining the basic exit codes for the resource: + +```jsonc +{ + // ellided manifest definition + "exitCodes": { + "0": "success", + "1": "unknown failure" + } +} +``` + +When the resource developer adds handling for a data validation failure, they define the new exit +code as `64`, the first recommended custom exit code for a resource that supports Linux and Unix +operating systems: + +```jsonc +{ + // ellided manifest definition + "exitCodes": { + "0": "success", + "1": "unknown failure", + "64": "invalid data" + } +} +``` + +The next exit code the resource developer defines for this resource should use exit code `65`. + +### Example 2: Semantic exit code ranges + +For this example resource, the developer has defined ranges for the resource operation exit codes: + +- `70` through `79` for validation errors, where `70` is a catch-all for validation errors that + don't have their own exit code. +- `80` through `89` for authentication errors, where `80` is a catch-all for authentication errors + that don't have their own exit code. +- `90` through `99` for operational errors, where `90` is a catch-all for operational errors that + don't have their own exit code. + +```jsonc +{ + // ellided manifest definition + "exitCodes": { + "0": "success", + "1": "unknown failure", + "70": "data validation failure", + "80": "authentication failure", + "90": "operational failure" + } +} +``` + +When the resource adds handling for a specific data validation failure, the manifest would define +the exit code for that failure as `71`. + +## Related content + +- [Designing a DSC resource](./index.md) +- [Emitting messages from a DSC resource](./emitting-messages.md) diff --git a/docs/concepts/resources/authoring/exporter/resource-manifest.md b/docs/concepts/resources/authoring/exporter/resource-manifest.md new file mode 100644 index 00000000..4364610d --- /dev/null +++ b/docs/concepts/resources/authoring/exporter/resource-manifest.md @@ -0,0 +1,42 @@ +--- +description: >- + Considerations and guidance for authoring the document that defines an exporter resource. +ms.date: 08/15/2025 +title: Authoring a DSC exporter resource manifest +--- + +# Authoring a DSC exporter resource manifest + + + +## Defining the initial manifest + + + +## Defining operations + + + +### Defining export + + + +## Defining exit codes + + + +## Best practices + + diff --git a/docs/concepts/resources/authoring/index.md b/docs/concepts/resources/authoring/index.md new file mode 100644 index 00000000..faef0f40 --- /dev/null +++ b/docs/concepts/resources/authoring/index.md @@ -0,0 +1,64 @@ +--- +description: >- + Overview of the process and considerations for designing a DSC resource. +ms.date: 03/25/2025 +title: Designing a DSC resource +--- + +# Designing a DSC resource + + + +## Choosing a resource kind + +When you decide to implement a DSC resource, you need to determine what _kind_ of resource you're +developing. DSC supports several different kinds of resource: + +- Typical resources manage the state of a configurable component. Most resources are typical + resources. +- Adapter resources make noncommand resources available to DSC to enable resource authors to + develop resources without defining a manifest and executable. +- Exporter resources enable recursive export operations to help users quickly export the current + configuration of a system without having to know every available resource. + +For specific guidance on authoring resources, see: + +- [Authoring a typical DSC resource manifest](./typical/resource-manifest.md) and + [Authoring a typical DSC resource instance JSON Schema](./typical/resource-instance-schema.md) +- [Authoring a DSC exporter resource manifest](./exporter/resource-manifest.md) + +## Defining resource metadata + +DSC relies on metadata defined in the resource manifest to identify and describe each resource. At +a minimum, resources must define their fully qualified type name and version. When you're creating +resources for shared usage or publishing the resource publicly, there are other useful metadata +fields to define, like the resource description and tags. + +For more information, see [Defining DSC resource manifest metadata](./manifest-metadata.md). + +## Defining exit codes + +DSC determines whether a resource operation executed successfully by checking the exit code for +the resource process: + +- DSC interprets exit code `0` as a successful operation. +- DSC interprets any nonzero exit code as a failed operation. + +Resources that don't define the `exitCodes` field in their manifest can only surface success or +failure to users. To provide a better user experience, you can define exit codes and their meaning +in the resource manifest. + +For more guidance on defining exit codes, see +[Defining exit codes for a DSC resource](./exit-codes.md). + +## Resource messaging + +DSC resources can emit messages to stderr that DSC consumes and surfaces to users. Resource authors +can emit these messages to provide context and helpful information to users. + +## Related content + +- [Defining DSC resource manifest metadata](./manifest-metadata.md) +- [Defining DSC resource operation invocations](./operation-invocations.md) +- [Defining exit codes for a DSC resource](./exit-codes.md) +- [Emitting messages from a DSC resource](./emitting-messages.md) diff --git a/docs/concepts/resources/authoring/manifest-metadata.md b/docs/concepts/resources/authoring/manifest-metadata.md new file mode 100644 index 00000000..da74f0e6 --- /dev/null +++ b/docs/concepts/resources/authoring/manifest-metadata.md @@ -0,0 +1,128 @@ +--- +description: >- + Considerations and guidance for defining metadata in a resource manifest. +ms.date: 08/15/2025 +title: Defining DSC resource manifest metadata +--- + +# Defining DSC resource manifest metadata + +DSC relies on metadata defined in the resource manifest to identify and describe each resource. The +following metadata fields are available for a resource manifest: + +- `type` (required) - The fully qualified type name for the resource. DSC uses this field to + uniquely identify a specific resource. +- `version` (required) - The semantic version of the resource. By default, when DSC finds more than + one manifest for a resource with the same `type`, DSC uses the newest version of that resource. +- `description` (optional, recommended) - Defines a short human-readable description for the + resource. This value is surfaced from the `dsc resource list` command and + can be used as a filter when searching for resources. +- `tags` (optional, recommended) - Defines one or more strings that indicate usage for the + resource. This value is surfaced from the `dsc resource list` command and can be used as a filter + when searching for resources. + +## Defining the resource type name + +DSC distinguishes resources by their fully qualified type name. A resource's fully qualified type +name uses namespacing to distinguish between resources and uniquely identify them. + +The syntax for a fully qualified type name is: + +```Syntax +[.][.][.]/ +``` + +- `` is a required component that indicates which person or organization is responsible for + implementing and maintaining the resource. +- ``, ``, and `` are optional values to create namespaces under the owner for + organizing resources. These components of the type name are optional. +- `` is a required component that indicates the resource's purpose and usage. The `` is + frequently used as shorthand for discussing a resource, like `OSInfo` instead of + `Microsoft/OSInfo`. + +The regular expression pattern DSC uses to validate type names is: + +```regex +^\w+(\.\w+){0,3}\/\w+$ +``` + +When you define the fully qualified type name for your resource, follow these guidelines: + +1. Always define `` for the resource. +1. Consider defining at least one namespace segment for the resource to ensure that related + resources can be grouped together and you can avoid name collisions for future resources. +1. When defining resources for a specific platform, indicate the platform as a namespace segment. +1. Define `` as a noun. The noun should semantically align with the component that the + resource manages, such as: + + - `Package` for a resource that installs, updates, and removes software packages. + - `User` for a resource that creates, updates, and removes users from a system. + - `Timezone` for a resource that sets the timezone for a system. + +Example type names: + +- `Microsoft.Linux.Apt/Package` +- `Microsoft.Python/Package` +- `Microsoft.Linux/User` +- `Microsoft.Windows/Timezone` +- `Microsoft.SqlServer/Database` +- `Microsoft.SqlServer.Database/Role` +- `TSToy.CLI/SettingsFile` + +## Defining the resource version + +The `version` field in a resource manifest defines the semantic version +([semver](https://semver.org/)) of the DSC resource. This version identifies the resource, not the +version of the application it manages. + +Follow semantic versioning guidance for versioning your resource. Always increment the major +version of your resource for breaking changes. + +By default, DSC uses the latest nonprerelease version of an available resource on a system. + +## Defining the resource description + +The `description` field in a resource manifest defines a short synopsis of the resource's purpose. + +The description is surfaced from the [dsc resource list](../../../reference/cli/resource/list.md) +command. Users can specify the +[--description](../../../reference/cli/resource/list.md#--description) option to filter resources +by their description. + +When you define the description for your resource, follow these guidelines: + +- Keep the description short, no more than 80 characters. +- Don't use any newlines in the description. +- Write the description as a complete sentence in the imperative tense to indicate what you can use + the resource to do. +- If the resource doesn't implement set, start the description with `Returns information`. +- If the description requires any markup, use Markdown syntax sparingly. Only use inline syntax. + +Examples: + +- Manage Windows registry keys and values. +- Return information about the operating system. +- Adapt PowerShell DSC (PSDSC) resources implemented as PowerShell classes. +- Manage software packages with `apt`. + +## Defining the resource tags + +The `tags` field defines a list of searchable terms for the resource. Each tag must be a string of +alphanumeric characters and underscores. No other characters are permitted. + +There are a few conventional tags for resources with specific semantics: + +- `Windows` - indicates that the resource is functional on Windows systems. +- `Linux` - indicates that the resource is functional on Linux systems. +- `macOS` - indicates that the resource is functional on macOS systems. + +When you define the tags for your resource, follow these guidelines: + +- Include any conventional tags that apply to your resource. +- Define a tag for every term you think users will frequently search for that should return your + resource. + +## Related content + +- [Designing a DSC resource](./index.md) +- [Command-based DSC Resource manifest schema reference](../../../reference/schemas/resource/manifest/root.md) diff --git a/docs/concepts/resources/authoring/operation-invocations.md b/docs/concepts/resources/authoring/operation-invocations.md new file mode 100644 index 00000000..ca8096f1 --- /dev/null +++ b/docs/concepts/resources/authoring/operation-invocations.md @@ -0,0 +1,259 @@ +--- +description: >- + Considerations and guidance for defining exit codes for a resource. +ms.date: 08/15/2025 +title: Defining DSC resource operation invocations +--- + +# Defining DSC resource operation invocations + +For non-adapted resources, DSC expects the resource manifest to indicate how DSC should invoke +operations for the resource. The model for invoking resource operations is the same across all +operations. + +At a minimum, the resource needs to define the name of the executable command for DSC to invoke +with the `executable` field. If the command requires any arguments, specify them with the `args` +field. + +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. + +To ensure DSC can send input to your resource, you must define the `input` property, one JSON input +argument in the `args` property array, or both. + +## Defining the executable and basic arguments + +The `executable` field 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. + +The `args` property defines the list of arguments to pass to the command. DSC passes the arguments +to the command in the order you define them. + +For example, consider the following operation definition snippet: + +```json +{ + "executable": "my-app", + "args": [ + "config", + "get", + "my-resource", + "--output-format", + "jsonline" + ] +} +``` + +To invoke this resource, DSC will run the following effective command: + +```sh +my-app config get my-resource --output-format jsonline +``` + +In this example, the resource hasn't defined how DSC should pass input to the command and therefore +can't accept any input. + +## Input handling + +Most resource operations need to be able to accept input. Deciding which model to use depends on +which option works best for your own development context. + +You can have DSC send input to your resource over stdin, as environment variables, or as an input +argument. + +### Handling input from stdin + +When you define the `input` field as `stdin`, DSC sends the input data for the operation to the +defined `executable` over stdin as a compressed JSON object. When you use this input option, your +resource is responsible for deserializing the input JSON object. + +Consider the following operation definition snippet: + +```json +{ + "executable": "my-resource", + "args": ["config", "get"], + "input": "stdin" +} +``` + +To invoke this example resource operation definition, DSC will run the following effective +commands: + +- POSIX shell + + ```sh + my-resource config get < $inputData + ``` + +- PowerShell + + ```powershell + $inputData | my-resource config get + ``` + +### Handling input from environment variables + +When you define the `input` field as `env`, DSC sends the input data for the operation to the +defined `executable` as one or more environment variables. This model enables you to author +resources without needing to handle parsing the input JSON but has some restrictions: + +- Your resource properties can only be the following JSON types: + + - `string` + - `boolean` + - `integer` + - `number` + - `array` where every item is of type `string`, `integer`, or `number`. + + If the input value for a property is `null`, DSC ignores that property when defining the + environment variables prior to invoking your resource. + + If the input value for a property is an object or an array containing any values that aren't a + string, integer, or number, DSC raises an error. +- DSC creates an environment variable for every defined property in the input object. +- The created environment variable uses the same casing as the property name. +- The value for the created environment variable is always a string. Your resource is responsible + for correctly interpreting non-string property values from their string representation. +- For array properties, the created environment variable separates each value with a comma. Your + resource shouldn't accept string values that contain any commas. DSC doesn't provide any handling + for escaping string values in an array that contain commas. +- DSC doesn't clear existing environment variables prior to invoking the command, so any + environment variables already defined in the context where a user is invoking DSC will be + inherited. Any existing environment variables with the same name are overwritten for the + operation invocation, but not modified for the context where DSC itself is invoked. + +The primary use case for this input model is to support authoring resources as POSIX shell scripts +without requiring dependencies for parsing JSON. Given the limitations for defining resources with +input as environment variables, you may want to use a different input handling model or require +users to have a JSON parsing tool (such as [jq](https://jqlang.org/)) available. + +Consider the following definition snippet and input data: + +```json +{ + "executable": "my-resource", + "args": ["config", "get"], + "input": "stdin" +} +``` + +```json +{ + "stringProperty": "foo", + "booleanProperty": true, + "integerProperty": 0, + "numberProperty": 1.2, + "arrayOfStringsProperty": ["a", "b", "c"], + "arrayOfIntegersProperty": [1, 2, 3], + "arrayOfNumbersProperty": [1.2, 2.3, 3.4], + "arrayOfMixedTypesProperty": ["a", 1, 1.2], + "arrayEmptyProperty": [], + "nullProperty": null +} +``` + +To invoke this example resource operation definition, DSC will run the following effective commands +for the given input data: + +- POSIX shell + + ```sh + export stringProperty="foo" + export booleanProperty="true" + export integerProperty="0" + export numberProperty="1.2" + export arrayOfStringsProperty="a,b,c" + export arrayOfIntegersProperty="1,2,3" + export arrayOfNumbersProperty="1.2,2.3,3.4" + export arrayOfMixedTypesProperty="a,1,1.2" + export arrayEmptyProperty="" + my-resource config get + ``` + +- PowerShell + + ```powershell + $env:stringProperty = 'foo' + $env:booleanProperty = 'true' + $env:integerProperty = '0' + $env:numberProperty = '1.2' + $env:arrayOfStringsProperty = 'a,b,c' + $env:arrayOfIntegersProperty = '1,2,3' + $env:arrayOfNumbersProperty = '1.2,2.3,3.4' + $env:arrayOfMixedTypesProperty = 'a,1,1.2' + $env:arrayEmptyProperty = '' + my-resource config get + ``` + +### Handling input from a JSON input argument + +To support sending input for an operation as an argument, you can define a JSON input argument in +the `args` field. When you do, 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 in the `args` field. + +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` field and don't define a JSON input argument, DSC can't pass the +input JSON to the resource. For any operation definition except `get` and `export`, this makes the +definition invalid. + +Consider the following operation definition snippet: + +```json +{ + "executable": "my-resource", + "args": [ + "config", + "get", + { "jsonInputArg": "--input", "mandatory": true } + ], +} +``` + +To invoke this example resource operation definition, DSC will run the following effective +commands: + +- POSIX shell + + ```sh + my-resource config get --input $inputData + ``` + +- PowerShell + + ```powershell + my-resource config get --input $inputData + ``` + +## Related content + +- [Designing a DSC resource](./index.md) +- [Command-based DSC Resource manifest schema reference](../../../reference/schemas/resource/manifest/root.md) diff --git a/docs/concepts/resources/authoring/toc.yml b/docs/concepts/resources/authoring/toc.yml new file mode 100644 index 00000000..684ad11a --- /dev/null +++ b/docs/concepts/resources/authoring/toc.yml @@ -0,0 +1,21 @@ +items: + - name: Overview + href: index.md + - name: Defining manifest metadata + href: manifest-metadata.md + - name: Defining exit codes + href: exit-codes.md + - name: Emitting messages + href: emitting-messages.md + - name: Defining operation invocations + href: defining-operation-invocations.md + - name: Typical resources + items: + - name: Resource manifest + href: typical/resource-manifest.md + - name: Resource instance schema + href: typical/resource-instance-schema.md + - name: Exporter resources + items: + - name: Resource manifest + href: exporter/resource-manifest.md diff --git a/docs/concepts/resources/authoring/typical/resource-instance-schema.md b/docs/concepts/resources/authoring/typical/resource-instance-schema.md new file mode 100644 index 00000000..c592b9e4 --- /dev/null +++ b/docs/concepts/resources/authoring/typical/resource-instance-schema.md @@ -0,0 +1,50 @@ +--- +description: >- + Considerations and guidance for defining the JSON Schema that represents an instance of a typical + DSC resource. +ms.date: 08/15/2025 +title: Authoring a typical DSC resource instance JSON Schema +--- + +# Authoring a DSC resource instance JSON Schema + + + +## Defining the initial schema + + + +## Handling whether an instance exists + + + +## Defining configurable properties + + + +## Defining read-only properties + + + +## Defining write-only properties + + + +## Handling complex schemas + + + +## Best practices + + \ No newline at end of file diff --git a/docs/concepts/resources/authoring/typical/resource-manifest.md b/docs/concepts/resources/authoring/typical/resource-manifest.md new file mode 100644 index 00000000..c34f234d --- /dev/null +++ b/docs/concepts/resources/authoring/typical/resource-manifest.md @@ -0,0 +1,72 @@ +--- +description: >- + Considerations and guidance for defining the document that defines a typical DSC resource. +ms.date: 08/15/2025 +title: Authoring a typical DSC resource manifest +--- + +# Authoring a typical DSC resource manifest + + + +## Defining the initial manifest + + + +## Defining operations + + + +### Defining get + + + +### Defining set + + + +### Defining whatIf + + + +### Defining test + + + +### Defining export + + + +### Defining delete + + + +## Defining exit codes + + + +## Best practices + +