terraform-provider-edge-con.../internal/provider/provider.go
2025-11-11 14:15:52 +01:00

224 lines
8.1 KiB
Go

package provider
import (
"context"
"os"
"github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
// Ensure the implementation satisfies the expected interfaces.
var (
_ provider.Provider = &edgeConnectProvider{}
)
// New is a helper function to simplify provider server and testing implementation.
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &edgeConnectProvider{
version: version,
}
}
}
// edgeConnectProvider is the provider implementation.
type edgeConnectProvider struct {
version string
}
// edgeConnectProviderModel maps provider schema data to a Go type.
type edgeConnectProviderModel struct {
BaseURL types.String `tfsdk:"base_url"`
Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
}
// Metadata returns the provider type name.
func (p *edgeConnectProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "edge-connect"
resp.Version = p.version
}
// Schema defines the provider-level schema for configuration data.
func (p *edgeConnectProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Interact with Edge Connect API for managing applications and application instances.",
Attributes: map[string]schema.Attribute{
"base_url": schema.StringAttribute{
Description: "The base URL for the Edge Connect API. May also be provided via EDGE_CONNECT_BASE_URL environment variable.",
Optional: true,
},
"token": schema.StringAttribute{
Description: "Bearer token for authentication. May also be provided via EDGE_CONNECT_TOKEN environment variable.",
Optional: true,
Sensitive: true,
},
"username": schema.StringAttribute{
Description: "Username for basic authentication. May also be provided via EDGE_CONNECT_USERNAME environment variable.",
Optional: true,
},
"password": schema.StringAttribute{
Description: "Password for basic authentication. May also be provided via EDGE_CONNECT_PASSWORD environment variable.",
Optional: true,
Sensitive: true,
},
},
}
}
// Configure prepares a Edge Connect API client for data sources and resources.
func (p *edgeConnectProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
tflog.Info(ctx, "Configuring Edge Connect client")
// Retrieve provider data from configuration
var config edgeConnectProviderModel
diags := req.Config.Get(ctx, &config)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
// If practitioner provided a configuration value for any of the
// attributes, it must be a known value.
if config.BaseURL.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("base_url"),
"Unknown Edge Connect API Base URL",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the base URL. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_BASE_URL environment variable.",
)
}
if config.Token.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("token"),
"Unknown Edge Connect API Token",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the token. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_TOKEN environment variable.",
)
}
if config.Username.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("username"),
"Unknown Edge Connect API Username",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the username. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_USERNAME environment variable.",
)
}
if config.Password.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("password"),
"Unknown Edge Connect API Password",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the password. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_PASSWORD environment variable.",
)
}
if resp.Diagnostics.HasError() {
return
}
// Default values to environment variables, but override
// with Terraform configuration value if set.
baseURL := os.Getenv("EDGE_CONNECT_BASE_URL")
token := os.Getenv("EDGE_CONNECT_TOKEN")
username := os.Getenv("EDGE_CONNECT_USERNAME")
password := os.Getenv("EDGE_CONNECT_PASSWORD")
if !config.BaseURL.IsNull() {
baseURL = config.BaseURL.ValueString()
}
if !config.Token.IsNull() {
token = config.Token.ValueString()
}
if !config.Username.IsNull() {
username = config.Username.ValueString()
}
if !config.Password.IsNull() {
password = config.Password.ValueString()
}
// If any of the expected configurations are missing, return
// errors with provider-specific guidance.
if baseURL == "" {
resp.Diagnostics.AddAttributeError(
path.Root("base_url"),
"Missing Edge Connect API Base URL",
"The provider requires a base URL for the Edge Connect API. "+
"Set the base_url value in the configuration or use the EDGE_CONNECT_BASE_URL environment variable. "+
"If either is already set, ensure the value is not empty.",
)
}
if token == "" && (username == "" || password == "") {
resp.Diagnostics.AddError(
"Missing Edge Connect API Authentication",
"The provider requires either a bearer token or username/password for authentication. "+
"Set the token value in the configuration or use the EDGE_CONNECT_TOKEN environment variable, "+
"or set username and password values in the configuration or use the EDGE_CONNECT_USERNAME and EDGE_CONNECT_PASSWORD environment variables.",
)
}
if resp.Diagnostics.HasError() {
return
}
ctx = tflog.SetField(ctx, "edge_connect_base_url", baseURL)
ctx = tflog.SetField(ctx, "edge_connect_token", token)
ctx = tflog.SetField(ctx, "edge_connect_username", username)
ctx = tflog.SetField(ctx, "edge_connect_password", password)
ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_token")
ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_password")
tflog.Debug(ctx, "Creating Edge Connect client")
// Create a new Edge Connect client using the configuration values
apiClient := client.NewClient(baseURL, token, username, password)
// Test the connection
if err := apiClient.HealthCheck(); err != nil {
resp.Diagnostics.AddError(
"Unable to Connect to Edge Connect API",
"An error occurred while connecting to the Edge Connect API. "+
"Please verify that your base URL and authentication credentials are correct.\n\n"+
"Edge Connect Client Error: "+err.Error(),
)
return
}
// Make the Edge Connect client available during DataSource and Resource
// type Configure methods.
resp.DataSourceData = apiClient
resp.ResourceData = apiClient
tflog.Info(ctx, "Configured Edge Connect client", map[string]any{"success": true})
}
// DataSources defines the data sources implemented in the provider.
func (p *edgeConnectProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewAppDataSource,
NewAppInstDataSource,
}
}
// Resources defines the resources implemented in the provider.
func (p *edgeConnectProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewAppResource,
NewAppInstResource,
}
}