Skip to content

Commit ae74f93

Browse files
authored
ephemeral: Initial ephemeral resource type implementation (#1050)
* 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] <[email protected]> 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 <[email protected]> * Update website/docs/plugin/framework/ephemeral-resources/validate-configuration.mdx Co-authored-by: Selena Goods <[email protected]> * adjust package docs ---------
1 parent a2137d3 commit ae74f93

File tree

216 files changed

+29854
-788
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

216 files changed

+29854
-788
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: ENHANCEMENTS
2+
body: 'provider: Added `ProviderWithEphemeralResources` interface for implementing
3+
ephemeral resources'
4+
time: 2024-10-28T13:04:57.796703-04:00
5+
custom:
6+
Issue: "1050"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: ENHANCEMENTS
2+
body: 'tfsdk: Added `EphemeralResultData` struct for representing ephemeral values
3+
produced by a provider, such as from an ephemeral resource'
4+
time: 2024-10-28T13:06:18.799164-04:00
5+
custom:
6+
Issue: "1050"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: ENHANCEMENTS
2+
body: 'provider: Added `EphemeralResourceData` to `ConfigureResponse`, to pass provider-defined
3+
data to `ephemeral.EphemeralResource` implementations'
4+
time: 2024-10-28T13:07:58.9914-04:00
5+
custom:
6+
Issue: "1050"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: FEATURES
2+
body: 'ephemeral: New package for implementing ephemeral resources'
3+
time: 2024-10-28T13:03:39.23218-04:00
4+
custom:
5+
Issue: "1050"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: FEATURES
2+
body: 'ephemeral/schema: New package for implementing ephemeral resource schemas'
3+
time: 2024-10-28T13:08:55.520004-04:00
4+
custom:
5+
Issue: "1050"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: NOTES
2+
body: Ephemeral resource support is in technical preview and offered without compatibility
3+
promises until Terraform 1.10 is generally available.
4+
time: 2024-10-28T13:03:08.373897-04:00
5+
custom:
6+
Issue: "1050"

ephemeral/close.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package ephemeral
4+
5+
import (
6+
"github.com/hashicorp/terraform-plugin-framework/diag"
7+
"github.com/hashicorp/terraform-plugin-framework/internal/privatestate"
8+
)
9+
10+
// CloseRequest represents a request for the provider to close an ephemeral
11+
// resource. An instance of this request struct is supplied as an argument to
12+
// the ephemeral resource's Close function.
13+
type CloseRequest struct {
14+
// Private is provider-defined ephemeral resource private state data
15+
// which was previously provided by the latest Open or Renew operation.
16+
//
17+
// Use the GetKey method to read data.
18+
Private *privatestate.ProviderData
19+
}
20+
21+
// CloseResponse represents a response to a CloseRequest. An
22+
// instance of this response struct is supplied as an argument
23+
// to the ephemeral resource's Close function, in which the provider
24+
// should set values on the CloseResponse as appropriate.
25+
type CloseResponse struct {
26+
// Diagnostics report errors or warnings related to closing the
27+
// resource. An empty slice indicates a successful operation with no
28+
// warnings or errors generated.
29+
Diagnostics diag.Diagnostics
30+
}

ephemeral/config_validator.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package ephemeral
4+
5+
import "context"
6+
7+
// ConfigValidator describes reusable EphemeralResource configuration validation functionality.
8+
type ConfigValidator interface {
9+
// Description describes the validation in plain text formatting.
10+
//
11+
// This information may be automatically added to ephemeral resource plain text
12+
// descriptions by external tooling.
13+
Description(context.Context) string
14+
15+
// MarkdownDescription describes the validation in Markdown formatting.
16+
//
17+
// This information may be automatically added to ephemeral resource Markdown
18+
// descriptions by external tooling.
19+
MarkdownDescription(context.Context) string
20+
21+
// ValidateEphemeralResource performs the validation.
22+
//
23+
// This method name is separate from the datasource.ConfigValidator
24+
// interface ValidateDataSource method name, provider.ConfigValidator
25+
// interface ValidateProvider method name, and resource.ConfigValidator
26+
// interface ValidateResource method name to allow generic validators.
27+
ValidateEphemeralResource(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
28+
}

ephemeral/configure.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package ephemeral
4+
5+
import (
6+
"github.com/hashicorp/terraform-plugin-framework/diag"
7+
)
8+
9+
// ConfigureRequest represents a request for the provider to configure an
10+
// ephemeral resource, i.e., set provider-level data or clients. An instance of
11+
// this request struct is supplied as an argument to the EphemeralResource type
12+
// Configure method.
13+
type ConfigureRequest struct {
14+
// ProviderData is the data set in the
15+
// [provider.ConfigureResponse.EphemeralResourceData] field. This data is
16+
// provider-specifc and therefore can contain any necessary remote system
17+
// clients, custom provider data, or anything else pertinent to the
18+
// functionality of the EphemeralResource.
19+
//
20+
// This data is only set after the ConfigureProvider RPC has been called
21+
// by Terraform.
22+
ProviderData any
23+
}
24+
25+
// ConfigureResponse represents a response to a ConfigureRequest. An
26+
// instance of this response struct is supplied as an argument to the
27+
// EphemeralResource type Configure method.
28+
type ConfigureResponse struct {
29+
// Diagnostics report errors or warnings related to configuring of the
30+
// EphemeralResource. An empty slice indicates a successful operation with no
31+
// warnings or errors generated.
32+
Diagnostics diag.Diagnostics
33+
}

ephemeral/deferred.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package ephemeral
5+
6+
const (
7+
// DeferredReasonUnknown is used to indicate an invalid `DeferredReason`.
8+
// Provider developers should not use it.
9+
DeferredReasonUnknown DeferredReason = 0
10+
11+
// DeferredReasonEphemeralResourceConfigUnknown is used to indicate that the resource configuration
12+
// is partially unknown and the real values need to be known before the change can be planned.
13+
DeferredReasonEphemeralResourceConfigUnknown DeferredReason = 1
14+
15+
// DeferredReasonProviderConfigUnknown is used to indicate that the provider configuration
16+
// is partially unknown and the real values need to be known before the change can be planned.
17+
DeferredReasonProviderConfigUnknown DeferredReason = 2
18+
19+
// DeferredReasonAbsentPrereq is used to indicate that a hard dependency has not been satisfied.
20+
DeferredReasonAbsentPrereq DeferredReason = 3
21+
)
22+
23+
// Deferred is used to indicate to Terraform that a change needs to be deferred for a reason.
24+
//
25+
// NOTE: This functionality is related to deferred action support, which is currently experimental and is subject
26+
// to change or break without warning. It is not protected by version compatibility guarantees.
27+
type Deferred struct {
28+
// Reason is the reason for deferring the change.
29+
Reason DeferredReason
30+
}
31+
32+
// DeferredReason represents different reasons for deferring a change.
33+
//
34+
// NOTE: This functionality is related to deferred action support, which is currently experimental and is subject
35+
// to change or break without warning. It is not protected by version compatibility guarantees.
36+
type DeferredReason int32
37+
38+
func (d DeferredReason) String() string {
39+
switch d {
40+
case 0:
41+
return "Unknown"
42+
case 1:
43+
return "Ephemeral Resource Config Unknown"
44+
case 2:
45+
return "Provider Config Unknown"
46+
case 3:
47+
return "Absent Prerequisite"
48+
}
49+
return "Unknown"
50+
}

ephemeral/doc.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// Package ephemeral contains all interfaces, request types, and response
5+
// types for an ephemeral resource implementation.
6+
//
7+
// In Terraform, an ephemeral resource is a concept which enables provider
8+
// developers to offer practitioners ephemeral values, which will not be stored
9+
// in any artifact produced by Terraform (plan/state). Ephemeral resources can
10+
// optionally implement renewal logic via the (EphemeralResource).Renew method
11+
// and cleanup logic via the (EphemeralResource).Close method.
12+
//
13+
// Ephemeral resources are not saved into the Terraform plan or state and can
14+
// only be referenced in other ephemeral values, such as provider configuration
15+
// attributes. Ephemeral resources are defined by a type/name, such as "examplecloud_thing",
16+
// a schema representing the structure and data types of configuration, and lifecycle logic.
17+
//
18+
// The main starting point for implementations in this package is the
19+
// EphemeralResource type which represents an instance of an ephemeral resource
20+
// that has its own configuration and lifecycle logic. The [ephemeral.EphemeralResource]
21+
// implementations are referenced by the [provider.ProviderWithEphemeralResources] type
22+
// EphemeralResources method, which enables the ephemeral resource practitioner usage.
23+
//
24+
// NOTE: Ephemeral resource support is experimental and exposed without compatibility promises until
25+
// these notices are removed.
26+
package ephemeral

ephemeral/ephemeral_resource.go

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package ephemeral
4+
5+
import (
6+
"context"
7+
)
8+
9+
// EphemeralResource represents an instance of an ephemeral resource type. This is the core
10+
// interface that all ephemeral resources must implement.
11+
//
12+
// Ephemeral resources can optionally implement these additional concepts:
13+
//
14+
// - Configure: Include provider-level data or clients via EphemeralResourceWithConfigure
15+
//
16+
// - Validation: Schema-based or entire configuration via EphemeralResourceWithConfigValidators
17+
// or EphemeralResourceWithValidateConfig.
18+
//
19+
// - Renew: Handle renewal of an expired remote object via EphemeralResourceWithRenew.
20+
// Ephemeral resources can indicate to Terraform when a renewal must occur via the RenewAt
21+
// response field of the Open/Renew methods. Renew cannot return new result data for the
22+
// ephemeral resource instance, so this logic is only appropriate for remote objects like
23+
// HashiCorp Vault leases, which can be renewed without changing their data.
24+
//
25+
// - Close: Allows providers to clean up the ephemeral resource via EphemeralResourceWithClose.
26+
//
27+
// NOTE: Ephemeral resource support is experimental and exposed without compatibility promises until
28+
// these notices are removed.
29+
type EphemeralResource interface {
30+
// Metadata should return the full name of the ephemeral resource, such as
31+
// examplecloud_thing.
32+
Metadata(context.Context, MetadataRequest, *MetadataResponse)
33+
34+
// Schema should return the schema for this ephemeral resource.
35+
Schema(context.Context, SchemaRequest, *SchemaResponse)
36+
37+
// Open is called when the provider must generate a new ephemeral resource. Config values
38+
// should be read from the OpenRequest and new response values set on the OpenResponse.
39+
Open(context.Context, OpenRequest, *OpenResponse)
40+
}
41+
42+
// EphemeralResourceWithRenew is an interface type that extends EphemeralResource to
43+
// include a method which the framework will call when Terraform detects that the
44+
// provider-defined returned RenewAt time for an ephemeral resource has passed. This RenewAt
45+
// response field can be set in the OpenResponse and RenewResponse.
46+
type EphemeralResourceWithRenew interface {
47+
EphemeralResource
48+
49+
// Renew is called when the provider must renew the ephemeral resource based on
50+
// the provided RenewAt time. This RenewAt response field can be set in the OpenResponse and RenewResponse.
51+
//
52+
// Renew cannot return new result data for the ephemeral resource instance, so this logic is only appropriate
53+
// for remote objects like HashiCorp Vault leases, which can be renewed without changing their data.
54+
Renew(context.Context, RenewRequest, *RenewResponse)
55+
}
56+
57+
// EphemeralResourceWithClose is an interface type that extends
58+
// EphemeralResource to include a method which the framework will call when
59+
// Terraform determines that the ephemeral resource can be safely cleaned up.
60+
type EphemeralResourceWithClose interface {
61+
EphemeralResource
62+
63+
// Close is called when the provider can clean up the ephemeral resource.
64+
// Config values may be read from the CloseRequest.
65+
Close(context.Context, CloseRequest, *CloseResponse)
66+
}
67+
68+
// EphemeralResourceWithConfigure is an interface type that extends EphemeralResource to
69+
// include a method which the framework will automatically call so provider
70+
// developers have the opportunity to setup any necessary provider-level data
71+
// or clients in the EphemeralResource type.
72+
type EphemeralResourceWithConfigure interface {
73+
EphemeralResource
74+
75+
// Configure enables provider-level data or clients to be set in the
76+
// provider-defined EphemeralResource type.
77+
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
78+
}
79+
80+
// EphemeralResourceWithConfigValidators is an interface type that extends EphemeralResource to include declarative validations.
81+
//
82+
// Declaring validation using this methodology simplifies implementation of
83+
// reusable functionality. These also include descriptions, which can be used
84+
// for automating documentation.
85+
//
86+
// Validation will include ConfigValidators and ValidateConfig, if both are
87+
// implemented, in addition to any Attribute or Type validation.
88+
type EphemeralResourceWithConfigValidators interface {
89+
EphemeralResource
90+
91+
// ConfigValidators returns a list of functions which will all be performed during validation.
92+
ConfigValidators(context.Context) []ConfigValidator
93+
}
94+
95+
// EphemeralResourceWithValidateConfig is an interface type that extends EphemeralResource to include imperative validation.
96+
//
97+
// Declaring validation using this methodology simplifies one-off
98+
// functionality that typically applies to a single ephemeral resource. Any documentation
99+
// of this functionality must be manually added into schema descriptions.
100+
//
101+
// Validation will include ConfigValidators and ValidateConfig, if both are
102+
// implemented, in addition to any Attribute or Type validation.
103+
type EphemeralResourceWithValidateConfig interface {
104+
EphemeralResource
105+
106+
// ValidateConfig performs the validation.
107+
ValidateConfig(context.Context, ValidateConfigRequest, *ValidateConfigResponse)
108+
}

ephemeral/metadata.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
package ephemeral
4+
5+
// MetadataRequest represents a request for the EphemeralResource to return metadata,
6+
// such as its type name. An instance of this request struct is supplied as
7+
// an argument to the EphemeralResource type Metadata method.
8+
type MetadataRequest struct {
9+
// ProviderTypeName is the string returned from
10+
// [provider.MetadataResponse.TypeName], if the Provider type implements
11+
// the Metadata method. This string should prefix the EphemeralResource type name
12+
// with an underscore in the response.
13+
ProviderTypeName string
14+
}
15+
16+
// MetadataResponse represents a response to a MetadataRequest. An
17+
// instance of this response struct is supplied as an argument to the
18+
// EphemeralResource type Metadata method.
19+
type MetadataResponse struct {
20+
// TypeName should be the full ephemeral resource type, including the provider
21+
// type prefix and an underscore. For example, examplecloud_thing.
22+
TypeName string
23+
}

0 commit comments

Comments
 (0)