liveBook · Manning

Configure function

As explained in Terraform in Depth: Infrastructure as Code with Terraform and OpenTofu

A configuration function is a provider implementation function that initializes or configures the client used to communicate with an external service.

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

How Terraform in Depth: Infrastructure as Code with Terraform and OpenTofu covers it

How deep it goes
Explains validation, Unknown values, precedence, diagnostics, authentication, and client retrieval, but not downstream CRUD or read logic.
Examples
Uses a Mastodon client, derived Kubernetes configuration, environment variables, access tokens, and ProviderData type assertions.
What it assumes
Assumes provider schemas and models exist, while teaching Unknown values, diagnostics, ProviderData, and expected client types.
What you can do after
Build it from scratch by validating provider inputs, creating a client, and wiring that client into data sources and resources.
How it connects
Connects provider configuration with data sources, resources, schemas, environment variables, diagnostics, and external-service clients.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Terraform in Depth: Infrastructure as Code with Terraform and OpenTofu. The section links point to the parts of the book it draws on.