Skip to content

Support defining options for extensions #1080

@michaeltlombardi

Description

@michaeltlombardi

Summary of the new feature / enhancement

As a developer working on a DSC extension,
I want to enable users to pass options to
the extension, so that my extension can
initialize with those options.

As a developer working on a DSC extension,
I want to advertise the options for my
extension and ensure those options can
be discovered and validated.

As a user,
I want to be able to define options for
my extensions in my DSC settings and policy,
so that I can ensure extensions behave as
expected and desired.

As a user,
I want to be able to specify options for
my extensions in my configuration documents,
so that I can ensure extensions behave as
expected and desired without managing my
DSC settings and policy between executions.

As an integrating developer,
I want to be able to inspect extension manifests
to determine whether they support any options and
understand how to ensure my integration handles
extension options gracefully.

Proposed technical implementation details (optional)

Currently, extensions don't have any way to support options. Any initialization requirements for an extension must be handled externally to DSC. We could support the declaration and definition of options as a field in the extension manifest like optionsSchema, where the value must be a JSON Schema describing the available options as an object.

We would also need a way to pass those options to the extension commands. The sooner we do so, the less disruptive it will be for extension authors. Unless/until we have support for long-running extensions (where we can send options once for initialization), we probably have to pass them for every extension operation. The first option that comes to mind is defining an ExtensionArg enum that supports an jsonOptionsArg similar to the jsonInputArg for resource operation commands.

Once extensions support defining a schema for their options, we could integrate defining extension options into DSC settings, policy, and configuration documents.

For settings and policy, we could initially support something like the following snippet:

extensions:
  allowedExtensions: [] # allow-list for extensions by type
  blockedExtensions: [] # block-list for extensions by type
  # remaining key-value pairs must be the type of an extension
  # followed by settings for that specific extension:
  Example.Feature/Ext:  # Applies only to `Example.Feature/Ext`
    enabled: true       # Doesn't override top-level keys
    options:            # Arbitrary map of options validated by manifest
      foo: true
      bar: baz

Which would look like this in rust (naming for clarity, not proposing these names):

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct DscGeneralExtensionSettings {
  #[serde(skip_serializing_if = "Option::is_none")]
  pub allowed_extensions: Option<Vec<String>>,
  #[serde(skip_serializing_if = "Option::is_none")]
  pub blocked_extensions: Option<Vec<String>>,
  // Everything else has to be a key-value pair where the key
  // is the type for an extension and the value is a valid
  // representation of ExtensionSettings.
  #[serde(flatten)]
  pub per_extension_settings: Option<HashMap<String, DscSpecificExtensionSettings>>,
}
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct DscSpecificExtensionSettings {
  #[serde(skip_serializing_if = "Option::is_none")]
  pub enabled: Option<bool>,
  // options is a free-form map - validation is
  // based on the defined schema for that extension
  #[serde(skip_serializing_if = "Option::is_none")]
  pub options: Option<Map<String, Value>>,
}

Similarly, we could reuse these structures in the Microsoft.Dsc field under metadata in a configuration document:

metadata:
  Microsoft.DSC:
    extensions:
      Example.Feature/Ext:
        options:
          foo: true
          bar: baz

We would need to be clear about behavior:

  • Settings for extensions at the policy level can't be overridden, but any extension not defined in policy can be defined in settings or in the configuration document.
  • Values for an extension in the configuration document override DSC settings.
  • If an extension exists and is disabled/blocked, we surface an error before invoking any resource operations. I don't think we have a generic way to check whether an extension is required/used in a configuration document at this time.
  • If an extension is defined in a configuration document as enabled but isn't available, we should warn or error as soon as possible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-EnhancementThe issue is a feature or ideaNeeds TriageSchema-ImpactChange requires updating a canonical schema for configs or manifests

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions