Skip to content

Allow arbitrary provider metadata to be generated for consumption by downstream tooling #1047

Open
@austinvalle

Description

@austinvalle

Module version

N/A

Use-cases

This feature is a follow-up to #1022 once that work is completed.

Once Framework providers are able to generate metadata that is defined by the schema (similar data to the terraform providers schema -json command today), we should consider allowing provider developers to define arbitrary data related to a resource/data source/provider that can be generated and included in the metadata JSON produced for downstream tools, an implementation that should be covered by #1022. For the specification of the metadata, we should explicitly declare where this arbitrary data will live, so downstream tools know where to expect it, similar to this idea for the code generation spec: hashicorp/terraform-plugin-codegen-spec#75

Once included in the metadata JSON output, this could be consumed by existing ecosystem tooling like terraform-plugin-docs or by provider-specific tooling.

A concrete example of where this could be useful can be found in the awscc provider: hashicorp/terraform-provider-awscc#2038

Proposal

As a lot of this relies on #1022, which hasn't been completely designed/implemented, this proposal is speculative

Since this would be at the schema level, we could leverage the Metadata response to provide this (ex. resource.MetadataResponse).

To put a straw-man proposal out there, one way to approach this could be accepting any type that implements the json.Marshaler interface:

type MetadataResponse struct {
    // .. other existing fields

    // CustomMetadata will generate provider-defined JSON data when creating Provider Metadata documents
    CustomMetadata json.Marshaler
}

With that, you could make a simple static metadata JSON marshaler from the map type (this could also be provided out of the box by terraform-plugin-framework):

func (r *thingResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
    resp.TypeName = req.ProviderTypeName + "_thing"

    resp.CustomMetadata = StaticMetadata(
        map[string]any{
            "create": map[string][]string{
                "permissions": {
                    "access-analyzer:CreateAnalyzer",
                    "access-analyzer:TagResource",
                    "iam:CreateServiceLinkedRole",
                    // etc.
                },
            },
        },
    )
}

func StaticMetadata(data map[string]any) staticMetadata {
    return staticMetadata{data: data}
}

type staticMetadata struct {
    data map[string]any
}

func (s staticMetadata) MarshalJSON() ([]byte, error) {
    return json.Marshal(s.data)
}

You could also write a more complex marshaler if defining the data statically isn't preferred, like the case of awscc, where a lot of the information is already defined in a separate JSON file: https://github.com/hashicorp/terraform-provider-awscc/blob/0c1486c2663aca8d80b347f260f1d140553c939a/internal/service/cloudformation/schemas/AWS_AccessAnalyzer_Analyzer.json#L171-L178

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions