Skip to content

Commit

Permalink
ephemeral: Initial ephemeral resource type implementation (#1050)
Browse files Browse the repository at this point in the history
* initial ephemeral resource interfaces

* add ephemeral resource configure data

* attribute implementations

* uncomment custom type tests

* added block implementations

* add nested attribute implementations

* add schema test

* remove todo

* doc updates, renames, removals

* initial protov5 + fwserver implementation (protov6 stubbed)

* add fromproto5 tests

* add toproto5 tests

* add proto5server tests

* implement protov6

* schema + metadata tests

* add close proto5/6 tests

* add fwserver tests for schema/metadata

* prevent random false positives

* validate fwserver tests

* open/renew/close fwserver tests

* update error message

* update plugin go

* remove `config` from renew

* remove state from renew/close, add deferred action support

* update doc comments

* add experimental note

* add changelogs

* initial website documentation

* build(deps): Bump github.com/hashicorp/terraform-plugin-go (#1051)

Bumps [github.com/hashicorp/terraform-plugin-go](https://github.com/hashicorp/terraform-plugin-go) from 0.24.0 to 0.25.0.
- [Release notes](https://github.com/hashicorp/terraform-plugin-go/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-go/blob/main/CHANGELOG.md)
- [Commits](hashicorp/terraform-plugin-go@v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/terraform-plugin-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update website/docs/plugin/framework/ephemeral-resources/renew.mdx

Co-authored-by: Selena Goods <selena.goods@hashicorp.com>

* Update website/docs/plugin/framework/ephemeral-resources/validate-configuration.mdx

Co-authored-by: Selena Goods <selena.goods@hashicorp.com>

* adjust package docs

---------
  • Loading branch information
austinvalle authored Oct 31, 2024
1 parent a2137d3 commit ae74f93
Show file tree
Hide file tree
Showing 216 changed files with 29,854 additions and 788 deletions.
6 changes: 6 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20241028-130457.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: ENHANCEMENTS
body: 'provider: Added `ProviderWithEphemeralResources` interface for implementing
ephemeral resources'
time: 2024-10-28T13:04:57.796703-04:00
custom:
Issue: "1050"
6 changes: 6 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20241028-130618.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: ENHANCEMENTS
body: 'tfsdk: Added `EphemeralResultData` struct for representing ephemeral values
produced by a provider, such as from an ephemeral resource'
time: 2024-10-28T13:06:18.799164-04:00
custom:
Issue: "1050"
6 changes: 6 additions & 0 deletions .changes/unreleased/ENHANCEMENTS-20241028-130758.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: ENHANCEMENTS
body: 'provider: Added `EphemeralResourceData` to `ConfigureResponse`, to pass provider-defined
data to `ephemeral.EphemeralResource` implementations'
time: 2024-10-28T13:07:58.9914-04:00
custom:
Issue: "1050"
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20241028-130339.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'ephemeral: New package for implementing ephemeral resources'
time: 2024-10-28T13:03:39.23218-04:00
custom:
Issue: "1050"
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20241028-130855.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'ephemeral/schema: New package for implementing ephemeral resource schemas'
time: 2024-10-28T13:08:55.520004-04:00
custom:
Issue: "1050"
6 changes: 6 additions & 0 deletions .changes/unreleased/NOTES-20241028-130308.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: NOTES
body: Ephemeral resource support is in technical preview and offered without compatibility
promises until Terraform 1.10 is generally available.
time: 2024-10-28T13:03:08.373897-04:00
custom:
Issue: "1050"
30 changes: 30 additions & 0 deletions ephemeral/close.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package ephemeral

import (
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
)

// CloseRequest represents a request for the provider to close an ephemeral
// resource. An instance of this request struct is supplied as an argument to
// the ephemeral resource's Close function.
type CloseRequest struct {
// Private is provider-defined ephemeral resource private state data
// which was previously provided by the latest Open or Renew operation.
//
// Use the GetKey method to read data.
Private *privatestate.ProviderData
}

// CloseResponse represents a response to a CloseRequest. An
// instance of this response struct is supplied as an argument
// to the ephemeral resource's Close function, in which the provider
// should set values on the CloseResponse as appropriate.
type CloseResponse struct {
// Diagnostics report errors or warnings related to closing the
// resource. An empty slice indicates a successful operation with no
// warnings or errors generated.
Diagnostics diag.Diagnostics
}
28 changes: 28 additions & 0 deletions ephemeral/config_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package ephemeral

import "context"

// ConfigValidator describes reusable EphemeralResource configuration validation functionality.
type ConfigValidator interface {
// Description describes the validation in plain text formatting.
//
// This information may be automatically added to ephemeral resource plain text
// descriptions by external tooling.
Description(context.Context) string

// MarkdownDescription describes the validation in Markdown formatting.
//
// This information may be automatically added to ephemeral resource Markdown
// descriptions by external tooling.
MarkdownDescription(context.Context) string

// ValidateEphemeralResource performs the validation.
//
// This method name is separate from the datasource.ConfigValidator
// interface ValidateDataSource method name, provider.ConfigValidator
// interface ValidateProvider method name, and resource.ConfigValidator
// interface ValidateResource method name to allow generic validators.
ValidateEphemeralResource(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
}
33 changes: 33 additions & 0 deletions ephemeral/configure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package ephemeral

import (
"github.com/hashicorp/terraform-plugin-framework/diag"
)

// ConfigureRequest represents a request for the provider to configure an
// ephemeral resource, i.e., set provider-level data or clients. An instance of
// this request struct is supplied as an argument to the EphemeralResource type
// Configure method.
type ConfigureRequest struct {
// ProviderData is the data set in the
// [provider.ConfigureResponse.EphemeralResourceData] field. This data is
// provider-specifc and therefore can contain any necessary remote system
// clients, custom provider data, or anything else pertinent to the
// functionality of the EphemeralResource.
//
// This data is only set after the ConfigureProvider RPC has been called
// by Terraform.
ProviderData any
}

// ConfigureResponse represents a response to a ConfigureRequest. An
// instance of this response struct is supplied as an argument to the
// EphemeralResource type Configure method.
type ConfigureResponse struct {
// Diagnostics report errors or warnings related to configuring of the
// EphemeralResource. An empty slice indicates a successful operation with no
// warnings or errors generated.
Diagnostics diag.Diagnostics
}
50 changes: 50 additions & 0 deletions ephemeral/deferred.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package ephemeral

const (
// DeferredReasonUnknown is used to indicate an invalid `DeferredReason`.
// Provider developers should not use it.
DeferredReasonUnknown DeferredReason = 0

// DeferredReasonEphemeralResourceConfigUnknown is used to indicate that the resource configuration
// is partially unknown and the real values need to be known before the change can be planned.
DeferredReasonEphemeralResourceConfigUnknown DeferredReason = 1

// DeferredReasonProviderConfigUnknown is used to indicate that the provider configuration
// is partially unknown and the real values need to be known before the change can be planned.
DeferredReasonProviderConfigUnknown DeferredReason = 2

// DeferredReasonAbsentPrereq is used to indicate that a hard dependency has not been satisfied.
DeferredReasonAbsentPrereq DeferredReason = 3
)

// Deferred is used to indicate to Terraform that a change needs to be deferred for a reason.
//
// NOTE: This functionality is related to deferred action support, which is currently experimental and is subject
// to change or break without warning. It is not protected by version compatibility guarantees.
type Deferred struct {
// Reason is the reason for deferring the change.
Reason DeferredReason
}

// DeferredReason represents different reasons for deferring a change.
//
// NOTE: This functionality is related to deferred action support, which is currently experimental and is subject
// to change or break without warning. It is not protected by version compatibility guarantees.
type DeferredReason int32

func (d DeferredReason) String() string {
switch d {
case 0:
return "Unknown"
case 1:
return "Ephemeral Resource Config Unknown"
case 2:
return "Provider Config Unknown"
case 3:
return "Absent Prerequisite"
}
return "Unknown"
}
26 changes: 26 additions & 0 deletions ephemeral/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

// Package ephemeral contains all interfaces, request types, and response
// types for an ephemeral resource implementation.
//
// In Terraform, an ephemeral resource is a concept which enables provider
// developers to offer practitioners ephemeral values, which will not be stored
// in any artifact produced by Terraform (plan/state). Ephemeral resources can
// optionally implement renewal logic via the (EphemeralResource).Renew method
// and cleanup logic via the (EphemeralResource).Close method.
//
// Ephemeral resources are not saved into the Terraform plan or state and can
// only be referenced in other ephemeral values, such as provider configuration
// attributes. Ephemeral resources are defined by a type/name, such as "examplecloud_thing",
// a schema representing the structure and data types of configuration, and lifecycle logic.
//
// The main starting point for implementations in this package is the
// EphemeralResource type which represents an instance of an ephemeral resource
// that has its own configuration and lifecycle logic. The [ephemeral.EphemeralResource]
// implementations are referenced by the [provider.ProviderWithEphemeralResources] type
// EphemeralResources method, which enables the ephemeral resource practitioner usage.
//
// NOTE: Ephemeral resource support is experimental and exposed without compatibility promises until
// these notices are removed.
package ephemeral
108 changes: 108 additions & 0 deletions ephemeral/ephemeral_resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package ephemeral

import (
"context"
)

// EphemeralResource represents an instance of an ephemeral resource type. This is the core
// interface that all ephemeral resources must implement.
//
// Ephemeral resources can optionally implement these additional concepts:
//
// - Configure: Include provider-level data or clients via EphemeralResourceWithConfigure
//
// - Validation: Schema-based or entire configuration via EphemeralResourceWithConfigValidators
// or EphemeralResourceWithValidateConfig.
//
// - Renew: Handle renewal of an expired remote object via EphemeralResourceWithRenew.
// Ephemeral resources can indicate to Terraform when a renewal must occur via the RenewAt
// response field of the Open/Renew methods. Renew cannot return new result data for the
// ephemeral resource instance, so this logic is only appropriate for remote objects like
// HashiCorp Vault leases, which can be renewed without changing their data.
//
// - Close: Allows providers to clean up the ephemeral resource via EphemeralResourceWithClose.
//
// NOTE: Ephemeral resource support is experimental and exposed without compatibility promises until
// these notices are removed.
type EphemeralResource interface {
// Metadata should return the full name of the ephemeral resource, such as
// examplecloud_thing.
Metadata(context.Context, MetadataRequest, *MetadataResponse)

// Schema should return the schema for this ephemeral resource.
Schema(context.Context, SchemaRequest, *SchemaResponse)

// Open is called when the provider must generate a new ephemeral resource. Config values
// should be read from the OpenRequest and new response values set on the OpenResponse.
Open(context.Context, OpenRequest, *OpenResponse)
}

// EphemeralResourceWithRenew is an interface type that extends EphemeralResource to
// include a method which the framework will call when Terraform detects that the
// provider-defined returned RenewAt time for an ephemeral resource has passed. This RenewAt
// response field can be set in the OpenResponse and RenewResponse.
type EphemeralResourceWithRenew interface {
EphemeralResource

// Renew is called when the provider must renew the ephemeral resource based on
// the provided RenewAt time. This RenewAt response field can be set in the OpenResponse and RenewResponse.
//
// Renew cannot return new result data for the ephemeral resource instance, so this logic is only appropriate
// for remote objects like HashiCorp Vault leases, which can be renewed without changing their data.
Renew(context.Context, RenewRequest, *RenewResponse)
}

// EphemeralResourceWithClose is an interface type that extends
// EphemeralResource to include a method which the framework will call when
// Terraform determines that the ephemeral resource can be safely cleaned up.
type EphemeralResourceWithClose interface {
EphemeralResource

// Close is called when the provider can clean up the ephemeral resource.
// Config values may be read from the CloseRequest.
Close(context.Context, CloseRequest, *CloseResponse)
}

// EphemeralResourceWithConfigure is an interface type that extends EphemeralResource to
// include a method which the framework will automatically call so provider
// developers have the opportunity to setup any necessary provider-level data
// or clients in the EphemeralResource type.
type EphemeralResourceWithConfigure interface {
EphemeralResource

// Configure enables provider-level data or clients to be set in the
// provider-defined EphemeralResource type.
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
}

// EphemeralResourceWithConfigValidators is an interface type that extends EphemeralResource to include declarative validations.
//
// Declaring validation using this methodology simplifies implementation of
// reusable functionality. These also include descriptions, which can be used
// for automating documentation.
//
// Validation will include ConfigValidators and ValidateConfig, if both are
// implemented, in addition to any Attribute or Type validation.
type EphemeralResourceWithConfigValidators interface {
EphemeralResource

// ConfigValidators returns a list of functions which will all be performed during validation.
ConfigValidators(context.Context) []ConfigValidator
}

// EphemeralResourceWithValidateConfig is an interface type that extends EphemeralResource to include imperative validation.
//
// Declaring validation using this methodology simplifies one-off
// functionality that typically applies to a single ephemeral resource. Any documentation
// of this functionality must be manually added into schema descriptions.
//
// Validation will include ConfigValidators and ValidateConfig, if both are
// implemented, in addition to any Attribute or Type validation.
type EphemeralResourceWithValidateConfig interface {
EphemeralResource

// ValidateConfig performs the validation.
ValidateConfig(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
}
23 changes: 23 additions & 0 deletions ephemeral/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package ephemeral

// MetadataRequest represents a request for the EphemeralResource to return metadata,
// such as its type name. An instance of this request struct is supplied as
// an argument to the EphemeralResource type Metadata method.
type MetadataRequest struct {
// ProviderTypeName is the string returned from
// [provider.MetadataResponse.TypeName], if the Provider type implements
// the Metadata method. This string should prefix the EphemeralResource type name
// with an underscore in the response.
ProviderTypeName string
}

// MetadataResponse represents a response to a MetadataRequest. An
// instance of this response struct is supplied as an argument to the
// EphemeralResource type Metadata method.
type MetadataResponse struct {
// TypeName should be the full ephemeral resource type, including the provider
// type prefix and an underscore. For example, examplecloud_thing.
TypeName string
}
Loading

0 comments on commit ae74f93

Please sign in to comment.