A configure function initializes the client that provider components use to communicate with an external service. At provider level, it validates configuration, resolves environment variables and provider values, reports diagnostics, and creates the client. Data sources and resources then retrieve that client through ProviderData. section 12.4.3 section 12.5.2
A robust provider-level configure function follows this sequence:
- Read the provider model and check every parameter for Unknown values, which can occur when configuration depends on resources created elsewhere. section 12.4.3
- Populate internal values from environment variables, then let non-null provider-block values override those defaults. section 12.4.3
- Validate complex relationships and formats, collecting all problems with attribute diagnostics instead of stopping at the first error. section 12.4.3
- Return immediately when diagnostics contain errors; otherwise create, authenticate, and return the external-service client. section 12.4.3
- In data sources and resources, safely obtain the expected client type from ProviderData and store it for later operations. section 12.5.2 section 12.6.2
Configuring a Mastodon client
A Mastodon provider reads the host, client credentials, and optional access token. It reports an actionable error when the host remains Unknown, chooses an authenticated or unauthenticated client configuration, creates the client, and verifies it by requesting the current user. An account data source or post resource subsequently extracts the client from ProviderData.
Listing 12.9 Provider configure attribute validation
func (p *MastodonProvider) Configure(ctx context.Context, req
provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var data MastodonProviderModel
tflog.Debug(ctx, "mastodon_provider configure")
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if data.Host.IsUnknown() { #1
resp.Diagnostics.AddAttributeError(
path.Root("host"), #2
"Unknown Mastodon API Host",
"The provider cannot create the Mastodon API client as there
is an unknown configuration value for the Mastodon API host. "+
"Either target apply the source of the value first, set
the value statically in the configuration, or use the MASTODON_HOST
environment variable.",
)
}
host := os.Getenv("MASTODON_HOST") #3
if !data.Host.IsNull() { #4
host = data.Host.ValueString()
}
if host == "" { #5
resp.Diagnostics.AddAttributeError(
path.Root("mastodon-host"), #6
"Missing Mastodon Credentials", #7
"The provider cannot create the Mastodon API client as the
Host is not set.", #8
)
}
/* client-id, client-secret, user-email, user-password, and
user-access-token follow the same pattern */
/* These blocks were excluded for brevity, but you should add them in
if you're running this locally. */
if access_token == "" && (user_email == "" || user_password == "") { #9
resp.Diagnostics.AddAttributeError(
path.Root("user-access-token"),
"Missing Mastodon Credentials",
"The provider cannot create the Mastodon API client as neither
the Access Token or the Username and Password fields are set.",
)
}
if resp.Diagnostics.HasError() { #10
return
}
}
#1 If the variable is in the special “unknown” state, we can’t use it and need to register an error.
#2 We have to update our import statement to include github.com/hashicorp/terraform-plugin-framework/path.
#3 First load the value from environment variables. This will default to an empty string.
#4 Now if the value is set in the configuration, we’ll use that instead.
#5 If the value isn’t set anywhere we need to register an error.
#6 We should call out the specific attribute that is missing.
#7 This is the title of the error.
#8 This is the description of the error.
#9 Now we have to confirm that we have either the access token or the username and password.
#10 If we have any errors, we need to stop here. By waiting until the end we can collect all of the errors and present them to the user at once.
Inspect the annotated provider implementation for Unknown-value handling and attribute diagnostics. section 12.4.3
Listing 12.13 Data source configure
func (d *AccountDataSource) Configure(ctx context.Context, req
datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
client, ok := req.ProviderData.(*mastodon.Client) #1
if !ok {
resp.Diagnostics.AddError( #2
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *mastodon.Client, got: %T. Please report
this issue to the provider developers.", req.ProviderData),
)
return
}
d.client = client #3
}
#1 Pluck the client out of the ProviderData object. Notice we changed the client type to *mastodon.Client.
#2 If the client is not the expected type, we add an error to the diagnostics.
#3 Assign the client to the data source client field.
Inspect the data-source implementation for nil protection, type assertions, diagnostics, and client assignment. section 12.5.2
