Data sources are an abstraction that allow Terraform to reference external data. Unlike managed resources, Terraform does not manage the lifecycle of the resource or data. Data sources are intended to have no side-effects.
This page describes the basic implementation details required for supporting a data source within the provider. Further documentation is available for deeper data source concepts:
Configure data sources with provider-level data types or clients.
Validate practitioner configuration against acceptable values.
In this example, a data source named examplecloud_thing with hardcoded behavior is defined:
// Ensure the implementation satisfies the desired interfaces.var_ datasource.DataSource =&ThingDataSource{}type ThingDataSource struct{}type ThingDataSourceModel struct{
ExampleAttribute types.String `tfsdk:"example_attribute"`
ID types.String `tfsdk:"id"`}func(d *ThingDataSource)Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse){
resp.TypeName ="examplecloud_thing"}func(d *ThingDataSource)GetSchema(ctx context.Context)(fwschema.Schema, diag.Diagnostics){return tfsdk.Schema{
Attributes:map[string]tfsdk.Attribute{"example_attribute":{
Required:true,
Type: types.StringType,},"id":{
Computed:true,
Type: types.StringType,},},},nil}func(d *ThingDataSource)Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse){var data ThingDataSourceModel
// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx,&data)...)// Typically data sources will make external calls, however this example// hardcodes setting the id attribute to a specific value for brevity.
data.ID = types.String{Value:"example-id"}// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx,&data)...)}
// Ensure the implementation satisfies the desired interfaces.var_ datasource.DataSource =&ThingDataSource{}type ThingDataSource struct{}type ThingDataSourceModel struct{ ExampleAttribute types.String `tfsdk:"example_attribute"` ID types.String `tfsdk:"id"`}func(d *ThingDataSource)Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse){ resp.TypeName ="examplecloud_thing"}func(d *ThingDataSource)GetSchema(ctx context.Context)(fwschema.Schema, diag.Diagnostics){return tfsdk.Schema{ Attributes:map[string]tfsdk.Attribute{"example_attribute":{ Required:true, Type: types.StringType,},"id":{ Computed:true, Type: types.StringType,},},},nil}func(d *ThingDataSource)Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse){var data ThingDataSourceModel
// Read Terraform configuration data into the model resp.Diagnostics.Append(req.Config.Get(ctx,&data)...)// Typically data sources will make external calls, however this example// hardcodes setting the id attribute to a specific value for brevity. data.ID = types.String{Value:"example-id"}// Save data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx,&data)...)}
The datasource.DataSource interface Metadata method defines the data source name as it would appear in Terraform configurations. This name should include the provider type prefix, an underscore, then the data source specific name. For example, a provider named examplecloud and a data source that reads "thing" resources would be named examplecloud_thing. Ensure the Add Data Source To Provider documentation is followed so the data source becomes part of the provider implementation, and therefore available to practitioners.
In this example, the data source name in an examplecloud provider that reads "thing" resources is hardcoded to examplecloud_thing:
// With the datasource.DataSource implementationfunc(d *ThingDataSource)Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse){
resp.TypeName ="examplecloud_thing"}
// With the datasource.DataSource implementationfunc(d *ThingDataSource)Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse){ resp.TypeName ="examplecloud_thing"}
The datasource.DataSource interface Read method defines how the data source updates Terraform's state to reflect the retrieved data. There is no plan or prior state to work with in Read requests, only configuration.
In this example, the ThingDataSource type, which implements the datasource.DataSource interface, is added to the provider implementation:
// With the provider.Provider implementationfunc(p *ExampleCloudProvider)DataSources(_ context.Context)[]func() datasource.DataSource {return[]func() datasource.DataSource{func() datasource.DataSource {return&ThingDataSource{},},}}
// With the provider.Provider implementationfunc(p *ExampleCloudProvider)DataSources(_ context.Context)[]func() datasource.DataSource {return[]func() datasource.DataSource{func() datasource.DataSource {return&ThingDataSource{},},}}
To simplify provider implementations, a named function can be created with the data source implementation.
In this example, the ThingDataSource code includes an additional NewThingDataSource function, which simplifies the provider implementation:
// With the provider.Provider implementationfunc(p *ExampleCloudProvider)DataSources(_ context.Context)[]func() datasource.DataSource {return[]func() datasource.DataSource{
NewThingDataSource,}}// With the datasource.DataSource implementationfuncNewThingDataSource() datasource.DataSource {return&ThingDataSource{}}
// With the provider.Provider implementationfunc(p *ExampleCloudProvider)DataSources(_ context.Context)[]func() datasource.DataSource {return[]func() datasource.DataSource{ NewThingDataSource,}}// With the datasource.DataSource implementationfuncNewThingDataSource() datasource.DataSource {return&ThingDataSource{}}