Skip to content

Commit 76cb83c

Browse files
committed
Updating "Simple Example Provider" following feedback (#418)
1 parent e305f7e commit 76cb83c

File tree

1 file changed

+77
-109
lines changed

1 file changed

+77
-109
lines changed

website/docs/plugin/framework/getting-started/example-provider.mdx

+77-109
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,39 @@ description: >-
66

77
# Simple Example Provider
88

9+
[Terraform providers](/terraform/language/providers) allow Terraform core to communicate with 3rd parties such as cloud providers, SaaS providers, and other APIs.
10+
Communication between Terraform core and Terraform providers uses gRPC, with core operating as a gRPC client and providers operating as gRPC servers, respectively.
11+
Terraform provider resources are used to manage infrastructure objects, such as virtual networks and compute instances.
12+
Terraform provider data sources give a read-only view of infrastructure objects.
13+
14+
The purpose of this example is to show the relationship between the components that are required to build a minimal Terraform provider.
15+
In a real provider the resource and data source would typically interact with a cloud provider via an API but in this example we are simply storing values in state.
16+
Stripping the Terraform provider back to the bare essentials allows us to focus on the minimum requirements needed to build a functional provider.
17+
918
A Terraform plugin provider requires the following as a minimum:
1019

11-
* main
20+
* provider server
1221
* provider
1322
* resource (and/or data source)
1423
* data source (and/or resource)
1524

16-
## Main
25+
A provider server is the gRPC server that the Terraform core gRPC client communicates with.
26+
The provider wraps the resource(s) and/or data source(s), and can be used to configure a client which communicates with a 3rd party service via an API.
27+
Resources are used to manage infrastructure objects.
28+
Data sources are used to read infrastructure objects.
29+
30+
## Provider Server
31+
32+
Each provider must implement a gRPC server that supports Terraform-specific connection and handshake handling on startup.
33+
34+
A [provider server](/plugin/framework/provider-servers) is required in order for a Terraform provider to:
35+
* expose resources that can be managed by Terraform core.
36+
* expose data sources that can be read by Terraform core.
37+
38+
The `main()` function is used for defining a provider server.
39+
40+
The `provider.New()` returns a function which returns a type that satisfies the `provider.Provider` interface.
41+
The `provider.Provider` interface defines functions for obtaining the resource(s) and/or data source(s) from a provider.
1742

1843
```go
1944
package main
@@ -47,13 +72,24 @@ func main() {
4772
}
4873
```
4974

50-
The `main()` function defines the [provider server](/plugin/framework/provider-servers).
75+
Refer to [Provider Servers](/plugin/framework/provider-servers) for more details.
76+
77+
## Provider
5178

52-
### provider.New()
79+
The provider wraps resources and data sources which are typically used for interacting with cloud providers, SaaS providers, or other APIs.
5380

54-
`provider.New()` returns a function which returns a type that satisfies the `provider.Provider` interface.
81+
In this example the provider wraps a resource and a data source which simply interact with Terraform state. Refer to the [tutorial](/tutorials/providers-plugin-framework/providers-plugin-framework-provider-configure) for an example of provider configuration that configures an API client.
5582

56-
## Provider
83+
`New()` returns a function which returns a type that satisfies the `provider.Provider` interface. The `New()` function is called by the [provider server](#provider-server) to obtain the provider.
84+
85+
The `exampleProvider` struct implements the `provider.Provider` interface. This interface defines the following functions:
86+
87+
- `Schema`: This function returns a provider `schema.Schema` struct that defines the provider schema. Schemas specify the constraints of Terraform configuration blocks. They define what fields a provider, resource, or data source configuration block has, and give Terraform metadata about those fields.
88+
- [`Configure`]((/plugin/framework/providers#configure-method)): This function lets you configure provider-level data or clients. These configuration values may be from the practitioner Terraform configuration, environment variables, or other means such as reading vendor-specific configuration files.
89+
- [`Resources`]((/plugin/framework/providers#resources)): This function returns a slice of functions that return types that implement the `resource.Resource` interface. Resources let Terraform manage infrastructure objects, such as a compute instance, an access policy, or disk.
90+
- [`DataSources`]((/plugin/framework/providers#datasources)): This function returns a slice of functions that return types which implement the `datasource.DataSource` interface. Data sources let Terraform reference external data. For example a database instance.
91+
92+
The `exampleProvider` struct also implements the `provider.ProviderWithMetadata` interface which defines the `Metadata` function. The `Metadata` function returns metadata for the provider such as a `TypeName` and `Version`. The `TypeName` is used as a prefix within a provider by for naming [resources](#resource) and [data sources](#data-source).
5793

5894
```go
5995
package provider
@@ -99,56 +135,27 @@ func (p *exampleProvider) Resources(ctx context.Context) []func() resource.Resou
99135
}
100136

101137
func (p *exampleProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
102-
resp.Schema = schema.Schema{
103-
Attributes: map[string]schema.Attribute{
104-
"configurable_attribute": schema.StringAttribute{
105-
Optional: true,
106-
},
107-
},
108-
}
109138
}
110139
```
111140

112-
### New
113-
114-
`New()` returns a function which returns a type that satisfies the `provider.Provider` interface.
115-
116-
### provider.Provider Interface
117-
118-
The `exampleProvider` struct implements the `provider.Provider` interface which defines the following 4 functions:
119-
120-
* Schema(context.Context, provider.SchemaRequest, *provider.SchemaResponse) (link needs adding)
121-
* [Configure(context.Context, ConfigureRequest, *ConfigureResponse)](/plugin/framework/providers#getschema-method)
122-
* [DataSources(context.Context) []func() datasource.DataSource](/plugin/framework/providers#datasources)
123-
* [Resources(context.Context) []func() resource.Resource](/plugin/framework/providers#resources)
124-
125-
#### Schema
141+
Refer to [Providers](/plugin/framework/providers) for more details and configuration examples.
126142

127-
`Schema(context.Context, provider.SchemaRequest, *provider.SchemaResponse)` returns a provider `schema.Schema` struct which defines the provider schema.
128-
129-
#### Configure
130-
131-
`Configure(context.Context, ConfigureRequest, *ConfigureResponse)` configures the provider.
132-
133-
#### DataSources
134-
135-
`DataSources(context.Context)` returns a slice of functions that return types which implement the `datasource.DataSource` interface.
136-
137-
#### Resources
138-
139-
`Resources(context.Context)` returns a slice of functions that return types which implement the `resource.Resource` interface.
143+
## Resource
140144

141-
### provider.ProviderWithMetadata Interface
145+
A resource is typically used to manage infrastructure objects such as virtual networks and compute instances.
142146

143-
The `exampleProvider` struct also implements the `provider.ProviderWithMetadata` interface which defines the following function:
147+
In this example the resource simply interacts with Terraform state.
144148

145-
* Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse)
149+
`NewResource()` returns a function which returns a type that satisfies the `resource.Resource` interface. The `NewResource()` function is used within the `provider.Resources` function to make the resource available to the provider.
146150

147-
#### Metadata
151+
The `exampleResource` struct implements the `resource.Resource` interface. This interface defines the following functions:
148152

149-
`Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse)` returns metadata for the provider such as a `TypeName` and `Version`.
150-
151-
## Resource
153+
- [`Metadata`](/plugin/framework/resources#metadata-method): This function returns the full name (`TypeName`) of the resource. The full name is used in [Terraform configuration](#resource-configuration) as `resource <full name> <alias>`.
154+
- `Schema`: This function returns a resource `schema.Schema` struct that defines the resource schema. The schema specifies the constraints of the resource Terraform configuration block. It defines what fields a resource configuration block has, and gives Terraform metadata about those fields. For instance, defining whether a field is required.
155+
- [`Create`](/plugin/framework/resources/create): This function lets the provider create a new resource of this type.
156+
- [`Read`](/plugin/framework/resources/read): This function lets the provider read resource values in order to update state.
157+
- [`Update`](/plugin/framework/resources/update): This function lets the provider update the resource and state.
158+
- [`Delete`](/plugin/framework/resources/delete): This function lets the provider delete the resource.
152159

153160
```go
154161
package provider
@@ -182,11 +189,9 @@ func (e *exampleResource) Schema(ctx context.Context, req resource.SchemaRequest
182189
Attributes: map[string]schema.Attribute{
183190
"configurable_attribute": schema.StringAttribute{
184191
Optional: true,
185-
MarkdownDescription: "Example configurable attribute",
186192
},
187193
"id": schema.StringAttribute{
188194
Computed: true,
189-
MarkdownDescription: "Example identifier",
190195
PlanModifiers: []planmodifier.String{
191196
stringplanmodifier.UseStateForUnknown(),
192197
},
@@ -210,6 +215,8 @@ func (e *exampleResource) Create(ctx context.Context, req resource.CreateRequest
210215
return
211216
}
212217

218+
// Create resource using 3rd party API.
219+
213220
data.Id = types.StringValue("example-id")
214221

215222
tflog.Trace(ctx, "created a resource")
@@ -228,6 +235,8 @@ func (e *exampleResource) Read(ctx context.Context, req resource.ReadRequest, re
228235
return
229236
}
230237

238+
// Read resource using 3rd party API.
239+
231240
diags = resp.State.Set(ctx, &data)
232241
resp.Diagnostics.Append(diags...)
233242
}
@@ -242,6 +251,8 @@ func (e *exampleResource) Update(ctx context.Context, req resource.UpdateRequest
242251
return
243252
}
244253

254+
// Update resource using 3rd party API.
255+
245256
diags = resp.State.Set(ctx, &data)
246257
resp.Diagnostics.Append(diags...)
247258
}
@@ -255,49 +266,26 @@ func (e *exampleResource) Delete(ctx context.Context, req resource.DeleteRequest
255266
if resp.Diagnostics.HasError() {
256267
return
257268
}
269+
270+
// Delete resource using 3rd party API.
258271
}
259272
```
260273

261-
### NewResource
262-
263-
`NewResource()` returns a function which returns a type that satisfies the `resource.Resource` interface.
264-
265-
### resource.Resource Interface
266-
267-
The `exampleResource` struct implements the `resource.Resource` interface which defines the following 6 functions:
268-
269-
* [Metadata(context.Context, MetadataRequest, *MetadataResponse)](/plugin/framework/resources#metadata-method)
270-
* Schema(context.Context, resource.SchemaRequest, *resource.SchemaResponse) (tfsdk.Schema, diag.Diagnostics) (link needs adding)
271-
* [Create(context.Context, CreateRequest, *CreateResponse)](/plugin/framework/resources/create)
272-
* [Read(context.Context, ReadRequest, *ReadResponse)](/plugin/framework/resources/read)
273-
* [Update(context.Context, UpdateRequest, *UpdateResponse)](/plugin/framework/resources/update)
274-
* [Delete(context.Context, DeleteRequest, *DeleteResponse)](/plugin/framework/resources/delete)
275-
276-
#### Metadata
277-
278-
`Metadata(context.Context, MetadataRequest, *MetadataResponse)` returns the full name (`TypeName`) of the resource.
279-
280-
#### Schema
281-
282-
`GetSchema(context.Context, resource.SchemaRequest, *resource.SchemaResponse)` returns a resource `schema.Schema` struct which defines the resource schema.
283-
284-
#### Create
274+
Refer to [Resources](/plugin/framework/resources) for more details and configuration examples.
285275

286-
`Create(context.Context, CreateRequest, *CreateResponse)` is called when the provider must create a new resource.
287-
288-
#### Read
289-
290-
`Read(context.Context, ReadRequest, *ReadResponse)` is called when the provider must read resource values in order to update state.
276+
## Data Source
291277

292-
### Update
278+
A data source is typically used to provide a read-only view of infrastructure objects.
293279

294-
`Update(context.Context, UpdateRequest, *UpdateResponse)` is called to update the state of the resource.
280+
In this example the data source simply interacts with Terraform state.
295281

296-
#### Delete
282+
`NewDataSource()` returns a function which returns a type that satisfies the `datasource.DataSource` interface. The `NewDataSource()` function is used within the `provider.DataSources` function to make the data source available to the provider.
297283

298-
`Delete(context.Context, DeleteRequest, *DeleteResponse)` is called when the provider must delete the resource.
284+
The `exampleDataSource` struct implements the `datasource.DataSource` interface. This interface defines the following functions:
299285

300-
## Data Source
286+
- [`Metadata`](/plugin/framework/data-sources#metadata-method): This function returns the full name (`TypeName`) of the data source. The full name is used in [Terraform configuration](#data-source-configuration) as `data <full name> <alias>`.
287+
- `Schema`: This function returns a data source `schema.Schema` struct that defines the data source schema. The schema specifies the constraints of the resource Terraform configuration block. It defines what fields a resource configuration block has, and gives Terraform metadata about those fields. For instance, defining whether a field is optional.
288+
- [`Read`]((/plugin/framework/data-sources#read-method)): This function lets the provider read data source values in order to update state.
301289

302290
```go
303291
package provider
@@ -355,6 +343,8 @@ func (e *exampleDataSource) Read(ctx context.Context, req datasource.ReadRequest
355343
return
356344
}
357345

346+
// Interact with 3rd party API to read data source.
347+
358348
data.Id = types.StringValue("example-id")
359349

360350
tflog.Trace(ctx, "read a data source")
@@ -364,33 +354,11 @@ func (e *exampleDataSource) Read(ctx context.Context, req datasource.ReadRequest
364354
}
365355
```
366356

367-
### NewDataSource
368-
369-
`NewDataSource()` returns a function which returns a type that satisfies the `datasource.DataSource` interface.
370-
371-
### datasource.DataSource Interface
372-
373-
The `exampleDataSource` struct implements the `datasource.DataSource` interface which defines the following 3 functions:
374-
375-
* [Metadata(context.Context, MetadataRequest, *MetadataResponse)](/plugin/framework/data-sources#metadata-method)
376-
* Schema(context.Context, datasource.SchemaRequest, *datasource.SchemaResponse) (link needs adding)
377-
* [Read(context.Context, ReadRequest, *ReadResponse)](/plugin/framework/data-sources#read-method)
378-
379-
#### Metadata
380-
381-
`Metadata(context.Context, MetadataRequest, *MetadataResponse)` returns the full name (`TypeName`) of the data source.
382-
383-
#### Schema
384-
385-
`Schema(context.Context, datasource.SchemaRequest, *datasource.SchemaResponse)` returns a data source `schema.Schema` struct which defines the data source schema.
386-
387-
#### Read
388-
389-
`Read(context.Context, ReadRequest, *ReadResponse)` is called when the provider must read data source values in order to update state.
357+
Refer to [Data Sources](/plugin/framework/data-sources) for more details and configuration examples.
390358

391359
## Terraform Configuration
392360

393-
Once a plugin provider has been defined, it is executed by specifying configuration and running `terraform apply`.
361+
With the definitions we have for [provider server](#provider-server), [provider](#provider), [resource](#resource) and [data source](#data-source), we can run the provider by specifying configuration and executing `terraform apply`.
394362

395363
### Resource Configuration
396364

@@ -402,7 +370,7 @@ resource "example_resource" "example" {
402370

403371
The `configurable_attribute` is defined within the [schema](#resource) as a string type attribute.
404372

405-
Examples of the various types of attributes and their representation within Terraform configuration and schema definitions is detailed in Core Concepts. (link needs adding)
373+
Examples of the various types of attributes and their representation within Terraform configuration and schema definitions is detailed in [Core Concepts](/plugin/framework/getting-started/core-concepts).
406374

407375
### Data Source Configuration
408376

@@ -414,4 +382,4 @@ data "example_datasource" "example" {
414382

415383
The `configurable_attribute` is defined within the [schema](#data-source) as a string type attribute.
416384

417-
Examples of the various types of attributes and their representation within Terraform configuration and schema definitions is detailed in Core Concepts. (link needs adding)
385+
Examples of the various types of attributes and their representation within Terraform configuration and schema definitions is detailed in [Core Concepts](/plugin/framework/getting-started/core-concepts).

0 commit comments

Comments
 (0)