Support beta functionality (#412)
* support beta functionality * add testing, improve logic and code quality * improve testing and code quality * Fix warning message
This commit is contained in:
parent
890e38f22a
commit
a07ff3f9ba
4 changed files with 288 additions and 0 deletions
|
|
@ -34,6 +34,7 @@ type ProviderData struct {
|
|||
SecretsManagerCustomEndpoint string
|
||||
SQLServerFlexCustomEndpoint string
|
||||
SKECustomEndpoint string
|
||||
EnableBetaResources bool
|
||||
}
|
||||
|
||||
// DiagsToError Converts TF diagnostics' errors into an error with a human-readable description.
|
||||
|
|
@ -66,3 +67,17 @@ func LogAndAddWarning(ctx context.Context, diags *diag.Diagnostics, summary, det
|
|||
tflog.Warn(ctx, fmt.Sprintf("%s | %s", summary, detail))
|
||||
diags.AddWarning(summary, detail)
|
||||
}
|
||||
|
||||
func LogAndAddWarningBeta(ctx context.Context, diags *diag.Diagnostics, name string) {
|
||||
warnTitle := fmt.Sprintf("The resource %q is in BETA", name)
|
||||
warnContent := fmt.Sprintf("The resource %q is in BETA and may be subject to breaking changes in the future. Use with caution.", name)
|
||||
tflog.Warn(ctx, fmt.Sprintf("%s | %s", warnTitle, warnContent))
|
||||
diags.AddWarning(warnTitle, warnContent)
|
||||
}
|
||||
|
||||
func LogAndAddErrorBeta(ctx context.Context, diags *diag.Diagnostics, name string) {
|
||||
errTitle := fmt.Sprintf("The resource %q is in BETA and BETA is not enabled", name)
|
||||
errContent := fmt.Sprintf("The resource %q is in BETA and the BETA functionality is currently not enabled. Please refer to the documentation on how to enable the BETA functionality.", name)
|
||||
tflog.Error(ctx, fmt.Sprintf("%s | %s", errTitle, errContent))
|
||||
diags.AddError(errTitle, errContent)
|
||||
}
|
||||
|
|
|
|||
48
stackit/internal/features/beta.go
Normal file
48
stackit/internal/features/beta.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package features
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
||||
)
|
||||
|
||||
// BetaResourcesEnabled returns whether this provider has BETA functionality enabled.
|
||||
//
|
||||
// In order of precedence, beta functionality can be managed by:
|
||||
// - Environment Variable `STACKIT_TF_ENABLE_BETA_RESOURCES` - `true` is enabled, `false` is disabled.
|
||||
// - Provider configuration feature flag `enable_beta` - `true` is enabled, `false` is disabled.
|
||||
func BetaResourcesEnabled(ctx context.Context, data *core.ProviderData, diags *diag.Diagnostics) bool {
|
||||
value, set := os.LookupEnv("STACKIT_TF_ENABLE_BETA_RESOURCES")
|
||||
if set {
|
||||
if strings.EqualFold(value, "true") {
|
||||
return true
|
||||
}
|
||||
if strings.EqualFold(value, "false") {
|
||||
return false
|
||||
}
|
||||
warnDetails := fmt.Sprintf(`The value of the environment variable that enables BETA functionality must be either "true" or "false", got %q.
|
||||
Defaulting to the provider feature flag.`, value)
|
||||
core.LogAndAddWarning(ctx, diags, "Invalid value for STACKIT_TF_ENABLE_BETA_RESOURCES environment variable.", warnDetails)
|
||||
}
|
||||
// ProviderData should always be set, but we check just in case
|
||||
if data == nil {
|
||||
return false
|
||||
}
|
||||
return data.EnableBetaResources
|
||||
}
|
||||
|
||||
// CheckBetaResourcesEnabled is a helper function to log and add a warning or error if the BETA functionality is not enabled.
|
||||
//
|
||||
// Should be called in the Configure method of a BETA resource.
|
||||
// Then, check for Errors in the diags using the diags.HasError() method.
|
||||
func CheckBetaResourcesEnabled(ctx context.Context, data *core.ProviderData, diags *diag.Diagnostics, resourceName string) {
|
||||
if !BetaResourcesEnabled(ctx, data, diags) {
|
||||
core.LogAndAddErrorBeta(ctx, diags, resourceName)
|
||||
return
|
||||
}
|
||||
core.LogAndAddWarningBeta(ctx, diags, resourceName)
|
||||
}
|
||||
216
stackit/internal/features/beta_test.go
Normal file
216
stackit/internal/features/beta_test.go
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
package features
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
|
||||
)
|
||||
|
||||
func TestBetaResourcesEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
data *core.ProviderData
|
||||
envSet bool
|
||||
envValue string
|
||||
expected bool
|
||||
expectWarn bool
|
||||
}{
|
||||
{
|
||||
description: "Feature flag enabled, env var not set",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: true,
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
description: "Feature flag is disabled, env var not set",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: false,
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag, Env var not set",
|
||||
data: &core.ProviderData{},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag not set, Env var is true",
|
||||
data: &core.ProviderData{},
|
||||
envSet: true,
|
||||
envValue: "true",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
description: "Feature flag not set, Env var is false",
|
||||
data: &core.ProviderData{},
|
||||
envSet: true,
|
||||
envValue: "false",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag not set, Env var is empty",
|
||||
data: &core.ProviderData{},
|
||||
envSet: true,
|
||||
envValue: "",
|
||||
expectWarn: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag not set, Env var is gibberish",
|
||||
data: &core.ProviderData{},
|
||||
envSet: true,
|
||||
envValue: "gibberish",
|
||||
expectWarn: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag enabled, Env var is true",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: true,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "true",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
description: "Feature flag enabled, Env var is false",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: true,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "false",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag enabled, Env var is empty",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: true,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "",
|
||||
expectWarn: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
description: "Feature flag enabled, Env var is gibberish",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: true,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "gibberish",
|
||||
expectWarn: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
description: "Feature flag disabled, Env var is true",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: false,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "true",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
description: "Feature flag disabled, Env var is false",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: false,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "false",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag disabled, Env var is empty",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: false,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "",
|
||||
expectWarn: true,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
description: "Feature flag disabled, Env var is gibberish",
|
||||
data: &core.ProviderData{
|
||||
EnableBetaResources: false,
|
||||
},
|
||||
envSet: true,
|
||||
envValue: "gibberish",
|
||||
expectWarn: true,
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
if tt.envSet {
|
||||
t.Setenv("STACKIT_TF_ENABLE_BETA_RESOURCES", tt.envValue)
|
||||
}
|
||||
diags := diag.Diagnostics{}
|
||||
|
||||
result := BetaResourcesEnabled(context.Background(), tt.data, &diags)
|
||||
if result != tt.expected {
|
||||
t.Fatalf("Expected %t, got %t", tt.expected, result)
|
||||
}
|
||||
|
||||
if tt.expectWarn && diags.WarningsCount() == 0 {
|
||||
t.Fatalf("Expected warning, got none")
|
||||
}
|
||||
if !tt.expectWarn && diags.WarningsCount() > 0 {
|
||||
t.Fatalf("Expected no warning, got %d", diags.WarningsCount())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckBetaResourcesEnabled(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
betaEnabled bool
|
||||
expectError bool
|
||||
expectWarn bool
|
||||
}{
|
||||
{
|
||||
description: "Beta enabled, show warning",
|
||||
betaEnabled: true,
|
||||
expectWarn: true,
|
||||
},
|
||||
{
|
||||
description: "Beta disabled, show error",
|
||||
betaEnabled: false,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
var envValue string
|
||||
if tt.betaEnabled {
|
||||
envValue = "true"
|
||||
} else {
|
||||
envValue = "false"
|
||||
}
|
||||
t.Setenv("STACKIT_TF_ENABLE_BETA_RESOURCES", envValue)
|
||||
|
||||
diags := diag.Diagnostics{}
|
||||
CheckBetaResourcesEnabled(context.Background(), &core.ProviderData{}, &diags, "test")
|
||||
|
||||
if tt.expectError && diags.ErrorsCount() == 0 {
|
||||
t.Fatalf("Expected error, got none")
|
||||
}
|
||||
if !tt.expectError && diags.ErrorsCount() > 0 {
|
||||
t.Fatalf("Expected no error, got %d", diags.ErrorsCount())
|
||||
}
|
||||
|
||||
if tt.expectWarn && diags.WarningsCount() == 0 {
|
||||
t.Fatalf("Expected warning, got none")
|
||||
}
|
||||
if !tt.expectWarn && diags.WarningsCount() > 0 {
|
||||
t.Fatalf("Expected no warning, got %d", diags.WarningsCount())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -103,6 +103,7 @@ type providerModel struct {
|
|||
ResourceManagerCustomEndpoint types.String `tfsdk:"resourcemanager_custom_endpoint"`
|
||||
TokenCustomEndpoint types.String `tfsdk:"token_custom_endpoint"`
|
||||
JWKSCustomEndpoint types.String `tfsdk:"jwks_custom_endpoint"`
|
||||
EnableBetaResources types.Bool `tfsdk:"enable_beta_resources"`
|
||||
}
|
||||
|
||||
// Schema defines the provider-level schema for configuration data.
|
||||
|
|
@ -135,6 +136,7 @@ func (p *Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *pro
|
|||
"ske_custom_endpoint": "Custom endpoint for the Kubernetes Engine (SKE) service",
|
||||
"token_custom_endpoint": "Custom endpoint for the token API, which is used to request access tokens when using the key flow",
|
||||
"jwks_custom_endpoint": "Custom endpoint for the jwks API, which is used to get the json web key sets (jwks) to validate tokens when using the key flow",
|
||||
"enable_beta_resources": "Enable beta resources. Default is false.",
|
||||
}
|
||||
|
||||
resp.Schema = schema.Schema{
|
||||
|
|
@ -248,6 +250,10 @@ func (p *Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *pro
|
|||
Description: descriptions["jwks_custom_endpoint"],
|
||||
DeprecationMessage: "Validation using JWKS was removed, for being redundant with token validation done in the APIs. This field has no effect, and will be removed in a later update",
|
||||
},
|
||||
"enable_beta_resources": schema.BoolAttribute{
|
||||
Optional: true,
|
||||
Description: descriptions["enable_beta_resources"],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -344,6 +350,9 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest,
|
|||
if !(providerConfig.TokenCustomEndpoint.IsUnknown() || providerConfig.TokenCustomEndpoint.IsNull()) {
|
||||
sdkConfig.TokenCustomUrl = providerConfig.TokenCustomEndpoint.ValueString()
|
||||
}
|
||||
if !(providerConfig.EnableBetaResources.IsUnknown() || providerConfig.EnableBetaResources.IsNull()) {
|
||||
providerData.EnableBetaResources = providerConfig.EnableBetaResources.ValueBool()
|
||||
}
|
||||
roundTripper, err := sdkauth.SetupAuth(sdkConfig)
|
||||
if err != nil {
|
||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring provider", fmt.Sprintf("Setting up authentication: %v", err))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue