Skip to content

Commit 97f6267

Browse files
committed
initial website documentation
1 parent e21e631 commit 97f6267

Some content is hidden

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

44 files changed

+651
-9
lines changed

ephemeral/ephemeral_resource.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
//
1919
// - Renew: Handle renewal of an expired remote object via EphemeralResourceWithRenew.
2020
// 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 state data for the
21+
// response field of the Open/Renew methods. Renew cannot return new result data for the
2222
// ephemeral resource instance, so this logic is only appropriate for remote objects like
2323
// HashiCorp Vault leases, which can be renewed without changing their data.
2424
//
@@ -49,7 +49,7 @@ type EphemeralResourceWithRenew interface {
4949
// Renew is called when the provider must renew the ephemeral resource based on
5050
// the provided RenewAt time. This RenewAt response field can be set in the OpenResponse and RenewResponse.
5151
//
52-
// Renew cannot return new state data for the ephemeral resource instance, so this logic is only appropriate
52+
// Renew cannot return new result data for the ephemeral resource instance, so this logic is only appropriate
5353
// for remote objects like HashiCorp Vault leases, which can be renewed without changing their data.
5454
Renew(context.Context, RenewRequest, *RenewResponse)
5555
}

website/data/plugin-framework-nav-data.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,35 @@
265265
}
266266
]
267267
},
268+
{
269+
"title": "Ephemeral Resources",
270+
"routes": [
271+
{
272+
"title": "Overview",
273+
"path": "ephemeral-resources"
274+
},
275+
{
276+
"title": "Open",
277+
"path": "ephemeral-resources/open"
278+
},
279+
{
280+
"title": "Configure Clients",
281+
"path": "ephemeral-resources/configure"
282+
},
283+
{
284+
"title": "Validate Configuration",
285+
"path": "ephemeral-resources/validate-configuration"
286+
},
287+
{
288+
"title": "Renew",
289+
"path": "ephemeral-resources/renew"
290+
},
291+
{
292+
"title": "Close",
293+
"path": "ephemeral-resources/close"
294+
}
295+
]
296+
},
268297
{
269298
"title": "Handling Data",
270299
"routes": [
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
page_title: 'Plugin Development - Framework: Open Ephemeral Resources'
3+
description: >-
4+
How to implement ephemeral resource close in the provider development framework.
5+
---
6+
7+
# Close Ephemeral Resources
8+
9+
Close is an optional part of the Terraform lifecycle for an ephemeral resource, which is different from the [managed resource lifecycle](https://github.com/hashicorp/terraform/blob/main/docs/resource-instance-change-lifecycle.md). During any Terraform operation (like [`terraform plan`](/terraform/cli/commands/plan) or [`terraform apply`](/terraform/cli/commands/apply)), when an ephemeral resource's data is needed, Terraform initially retrieves that data with the [`Open`](/terraform/plugin/framework/ephemeral-resources/open) lifecycle handler. Once the ephemeral resource data is no longer needed, Terraform calls the provider `CloseEphemeralResource` RPC, in which the framework calls the [`ephemeral.EphemeralResourceWithClose` interface `Close` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResourceWithClose). The request contains any `Private` data set in the latest `Open` or `Renew` call.
10+
11+
`Close` is an optional lifecycle implementation for an ephemeral resource, other lifecycle implementations include:
12+
13+
- [Open](/terraform/plugin/framework/ephemeral-resources/open) an ephemeral resource by receiving Terraform configuration, retrieving a remote object, and returning ephemeral result data to Terraform.
14+
- [Renew](/terraform/plugin/framework/ephemeral-resources/renew) an expired remote object at a specified time.
15+
16+
## Define Close Method
17+
18+
The [`ephemeral.EphemeralResourceWithClose` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResourceWithClose) on the [`ephemeral.EphemeralResource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResource) implementation will enable close support for an ephemeral resource.
19+
20+
Implement the `Close` method by:
21+
22+
1. [Accessing private data](/terraform/plugin/framework/resources/private-state#reading-private-state-data) from [`ephemeral.CloseRequest.Private` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#CloseRequest.Private) needed to close the remote object.
23+
1. Performing logic or external calls to close the remote object.
24+
25+
If the logic needs to return [warning or error diagnostics](/terraform/plugin/framework/diagnostics), they can be added into the [`ephemeral.CloseResponse.Diagnostics` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#CloseResponse.Diagnostics).
26+
27+
In this example, an ephemeral resource named `examplecloud_thing` with hardcoded behavior is defined. `Private` data needed to execute `Close` is passed from the `Open` response:
28+
29+
```go
30+
var _ ephemeral.EphemeralResourceWithClose = (*ThingEphemeralResource)(nil)
31+
32+
// ThingEphemeralResource defines the ephemeral resource implementation, which also implements Close.
33+
type ThingEphemeralResource struct{}
34+
35+
type ThingEphemeralResourceModel struct {
36+
Name types.String `tfsdk:"name"`
37+
Token types.String `tfsdk:"token"`
38+
}
39+
40+
type ThingPrivateData struct {
41+
Name string `json:"name"`
42+
}
43+
44+
func (e *ThingEphemeralResource) Schema(ctx context.Context, req ephemeral.SchemaRequest, resp *ephemeral.SchemaResponse) {
45+
resp.Schema = schema.Schema{
46+
Attributes: map[string]schema.Attribute{
47+
"name": schema.StringAttribute{
48+
Description: "Name of the thing to retrieve a token for.",
49+
Required: true,
50+
},
51+
"token": schema.StringAttribute{
52+
Description: "Token for the thing.",
53+
Computed: true,
54+
},
55+
},
56+
}
57+
}
58+
59+
func (e *ThingEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
60+
var data ThingEphemeralResourceModel
61+
62+
// Read Terraform config data into the model
63+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
64+
if resp.Diagnostics.HasError() {
65+
return
66+
}
67+
68+
// Typically ephemeral resources will make external calls and reference returned data,
69+
// however this example hardcodes the setting of result and private data for brevity.
70+
data.Token = types.StringValue("token-123")
71+
72+
// When closing, pass along this data (error handling omitted for brevity).
73+
privateData, _ := json.Marshal(ThingPrivateData{Name: data.Name.ValueString()})
74+
resp.Private.SetKey(ctx, "thing_data", privateData)
75+
76+
// Save data into ephemeral result data
77+
resp.Diagnostics.Append(resp.Result.Set(ctx, &data)...)
78+
}
79+
80+
func (e *ThingEphemeralResource) Close(ctx context.Context, req ephemeral.CloseRequest, resp *ephemeral.CloseResponse) {
81+
privateBytes, diags := req.Private.GetKey(ctx, "thing_data")
82+
resp.Diagnostics.Append(diags...)
83+
if resp.Diagnostics.HasError() {
84+
return
85+
}
86+
87+
// Unmarshal private data (error handling omitted for brevity).
88+
var privateData ThingPrivateData
89+
json.Unmarshal(privateBytes, &privateData)
90+
91+
// Perform external call to close/clean up "thing" data
92+
}
93+
94+
```
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
page_title: 'Plugin Development - Framework: Configure Ephemeral Resources'
3+
description: >-
4+
How to configure ephemeral resources with provider data or clients in the provider development framework.
5+
---
6+
7+
# Configure Ephemeral Resources
8+
9+
[Ephemeral Resources](/terraform/plugin/framework/ephemeral-resources) may require provider-level data or remote system clients to operate correctly. The framework supports the ability to configure this data and/or clients once within the provider, then pass that information to ephemeral resources by adding the `Configure` method.
10+
11+
## Prepare Provider Configure Method
12+
13+
Implement the [`provider.ConfigureResponse.EphemeralResourceData` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ConfigureResponse.EphemeralResourceData) in the [`Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure). This value can be set to any type, whether an existing client or vendor SDK type, a provider-defined custom type, or the provider implementation itself. It is recommended to use pointer types so that ephemeral resources can determine if this value was configured before attempting to use it.
14+
15+
During execution of the [`terraform plan`](/terraform/cli/commands/plan) and [`terraform apply`](/terraform/cli/commands/apply) commands, Terraform calls the [`ConfigureProvider`](/terraform/plugin/framework/internals/rpcs#configureprovider-rpc) RPC, in which the framework calls the [`provider.Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure).
16+
17+
In this example, the Go standard library [`net/http.Client`](https://pkg.go.dev/net/http#Client) is configured in the provider, and made available for ephemeral resources:
18+
19+
```go
20+
// With the provider.Provider implementation
21+
func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
22+
resp.EphemeralResourceData = &http.Client{/* ... */}
23+
}
24+
```
25+
26+
In this example, the code defines an `ExampleClient` type that is made available for ephemeral resources:
27+
28+
```go
29+
type ExampleClient struct {
30+
/* ... */
31+
}
32+
33+
// With the provider.Provider implementation
34+
func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
35+
resp.EphemeralResourceData = &ExampleClient{/* ... */}
36+
}
37+
```
38+
39+
In this example, the `ExampleCloudProvider` type itself is made available for ephemeral resources:
40+
41+
```go
42+
// With the provider.Provider implementation
43+
type ExampleCloudProvider struct {
44+
/* ... */
45+
}
46+
47+
func (p *ExampleCloudProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
48+
resp.EphemeralResourceData = p
49+
}
50+
```
51+
52+
## Define Ephemeral Resource Configure Method
53+
54+
Implement the [`ephemeral.EphemeralResourceWithConfigure` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResourceWithConfigure) which receives the provider configured data from the [`Provider` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Configure) and saves it into the [`ephemeral.EphemeralResource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResource) implementation.
55+
56+
The [`ephemeral.EphemeralResourceWithConfigure` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResourceWithConfigure.Configure) is called during execution of the [`terraform validate`](/terraform/cli/commands/validate), [`terraform plan`](/terraform/cli/commands/plan) and [`terraform apply`](/terraform/cli/commands/apply) commands when the `ValidateEphemeralResourceConfig` RPC is sent. Additionally, the [`ephemeral.EphemeralResourceWithConfigure` interface `Configure` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResourceWithConfigure.Configure) is called during execution of the [`terraform plan`](/terraform/cli/commands/plan) and [`terraform apply`](/terraform/cli/commands/apply) commands when the `OpenEphemeralResource` RPC is sent.
57+
58+
-> Note that Terraform calling the `ValidateEphemeralResourceConfig` RPC would not call the [`ConfigureProvider`](/terraform/plugin/framework/internals/rpcs#configureprovider-rpc) RPC first, so implementations need to account for that situation. Configuration validation in Terraform occurs without provider configuration ("offline").
59+
60+
In this example, the provider configured the Go standard library [`net/http.Client`](https://pkg.go.dev/net/http#Client) which the ephemeral resource uses during `Open`:
61+
62+
```go
63+
// With the ephemeral.EphemeralResource implementation
64+
type ThingEphemeralResource struct {
65+
client *http.Client
66+
}
67+
68+
func (d *ThingEphemeralResource) Configure(ctx context.Context, req ephemeral.ConfigureRequest, resp *ephemeral.ConfigureResponse) {
69+
// Always perform a nil check when handling ProviderData because Terraform
70+
// sets that data after it calls the ConfigureProvider RPC.
71+
if req.ProviderData == nil {
72+
return
73+
}
74+
75+
client, ok := req.ProviderData.(*http.Client)
76+
77+
if !ok {
78+
resp.Diagnostics.AddError(
79+
"Unexpected Ephemeral Resource Configure Type",
80+
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
81+
)
82+
83+
return
84+
}
85+
86+
d.client = client
87+
}
88+
89+
func (d *ThingEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
90+
// Prevent panic if the provider has not been configured.
91+
if d.client == nil {
92+
resp.Diagnostics.AddError(
93+
"Unconfigured HTTP Client",
94+
"Expected configured HTTP client. Please report this issue to the provider developers.",
95+
)
96+
97+
return
98+
}
99+
100+
httpResp, err := d.client.Get("https://example.com")
101+
/* ... */
102+
}
103+
```
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
page_title: 'Plugin Development - Framework: Ephemeral Resources'
3+
description: >-
4+
How to build ephemeral resources in the provider development framework. Ephemeral
5+
resources allow Terraform to reference external data, while guaranteeing that this
6+
data will not be persisted in plan or state.
7+
---
8+
9+
# Ephemeral Resources
10+
11+
<Highlight>
12+
13+
Ephemeral resource support is in technical preview and offered without compatibility promises until Terraform 1.10 is generally available.
14+
15+
</Highlight>
16+
17+
[Ephemeral resources](/terraform/language/resources/ephemeral) are an abstraction that allows Terraform to reference external data. Unlike [data sources](/terraform/language/data-sources), Terraform guarantees that ephemeral resource data will not be persisted in plan or state artifacts. The data produced by an ephemeral resource can only be referenced in [specific ephemeral contexts](/terraform/language/resources/ephemeral#referencing-ephemeral-resources) or Terraform will throw an error.
18+
19+
This page describes the basic implementation details required for supporting an ephemeral resource within the provider. Ephemeral resources, as a part of their lifecycle, must implement:
20+
21+
- [Open](/terraform/plugin/framework/ephemeral-resources/open) an ephemeral resource by receiving Terraform configuration, retrieving a remote object, and returning ephemeral result data to Terraform.
22+
23+
Further documentation is available for deeper ephemeral resource concepts:
24+
25+
- [Configure](/terraform/plugin/framework/ephemeral-resources/configure) an ephemeral resource with provider-level data types or clients.
26+
- [Validate](/terraform/plugin/framework/ephemeral-resources/validate-configuration) practitioner configuration against acceptable values.
27+
- [Renew](/terraform/plugin/framework/ephemeral-resources/renew) an expired remote object at a specified time.
28+
- [Close](/terraform/plugin/framework/ephemeral-resources/close) a remote object when Terraform no longer needs the data.
29+
30+
## Define Ephemeral Resource Type
31+
32+
Implement the [`ephemeral.EphemeralResource` interface](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResource). Ensure the [Add Ephemeral Resource To Provider](#add-ephemeral-resource-to-provider) documentation is followed so the ephemeral resource becomes part of the provider implementation, and therefore available to practitioners.
33+
34+
### Metadata Method
35+
36+
The [`ephemeral.EphemeralResource` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResource.Metadata) defines the ephemeral resource name as it would appear in Terraform configurations. This name should include the provider type prefix, an underscore, then the ephemeral resource specific name. For example, a provider named `examplecloud` and an ephemeral resource that reads "thing" ephemeral data would be named `examplecloud_thing`.
37+
38+
In this example, the ephemeral resource name in an `examplecloud` provider that reads "thing" ephemeral resource data is hardcoded to `examplecloud_thing`:
39+
40+
```go
41+
// With the ephemeral.EphemeralResource implementation
42+
func (r *ThingEphemeralResource) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
43+
resp.TypeName = "examplecloud_thing"
44+
}
45+
```
46+
47+
To simplify ephemeral resource implementations, the [`provider.MetadataResponse.TypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#MetadataResponse.TypeName) from the [`provider.Provider` interface `Metadata` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#Provider.Metadata) can set the provider name so it is available in the [`ephemeral.MetadataRequest.ProviderTypeName` field](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#MetadataRequest.ProviderTypeName).
48+
49+
In this example, the provider defines the `examplecloud` name for itself, and the ephemeral resource is named `examplecloud_thing`:
50+
51+
```go
52+
// With the provider.Provider implementation
53+
func (p *ExampleCloudProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
54+
resp.TypeName = "examplecloud"
55+
}
56+
57+
// With the ephemeral.EphemeralResource implementation
58+
func (d *ThingEphemeralResource) Metadata(ctx context.Context, req ephemeral.MetadataRequest, resp *ephemeral.MetadataResponse) {
59+
resp.TypeName = req.ProviderTypeName + "_thing"
60+
}
61+
```
62+
63+
### Schema Method
64+
65+
The [`ephemeral.EphemeralResource` interface `Schema` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/ephemeral#EphemeralResource.Schema) defines a [schema](/terraform/plugin/framework/handling-data/schemas) describing what data is available in the ephemeral resource's configuration and result data.
66+
67+
## Add Ephemeral Resource to Provider
68+
69+
Ephemeral resources become available to practitioners when they are included in the [provider](/terraform/plugin/framework/providers) implementation via the optional [`provider.ProviderWithEphemeralResources` interface `EphemeralResources` method](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework/provider#ProviderWithEphemeralResources.EphemeralResource).
70+
71+
In this example, the `ThingEphemeralResource` type, which implements the `ephemeral.EphemeralResource` interface, is added to the provider implementation:
72+
73+
```go
74+
var _ provider.ProviderWithEphemeralResources = (*ExampleCloudProvider)(nil)
75+
76+
func (p *ExampleCloudProvider) EphemeralResources(_ context.Context) []func() ephemeral.EphemeralResource {
77+
return []func() ephemeral.EphemeralResource{
78+
func() ephemeral.EphemeralResource {
79+
return &ThingResource{},
80+
},
81+
}
82+
}
83+
```
84+
85+
To simplify provider implementations, a named function can be created with the ephemeral resource implementation.
86+
87+
In this example, the `ThingEphemeralResource` code includes an additional `NewThingEphemeralResource` function, which simplifies the provider implementation:
88+
89+
```go
90+
// With the provider.ProviderWithEphemeralResources implementation
91+
func (p *ExampleCloudProvider) EphemeralResources(_ context.Context) []func() ephemeral.EphemeralResource {
92+
return []func() ephemeral.EphemeralResource{
93+
NewThingEphemeralResource,
94+
}
95+
}
96+
97+
// With the ephemeral.EphemeralResource implementation
98+
func NewThingEphemeralResource() ephemeral.EphemeralResource {
99+
return &ThingEphemeralResource{}
100+
}
101+
```

0 commit comments

Comments
 (0)