Files
coder/coderd/dynamicparameters/static.go
Steven Masley 659b787b9f chore: set wsbuilder to use preview parameters (#18474)
Use richer `previewtypes.Parameter` for `wsbuilder`. This is a pre-requirement to adding dynamic parameter validation.

The richer type contains more information than the `db` parameter, so the conversion is lossless.
2025-06-23 11:31:53 -05:00

148 lines
4.5 KiB
Go

package dynamicparameters
import (
"context"
"encoding/json"
"github.com/google/uuid"
"github.com/hashicorp/hcl/v2"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/db2sdk"
"github.com/coder/coder/v2/coderd/util/ptr"
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/preview"
previewtypes "github.com/coder/preview/types"
"github.com/coder/terraform-provider-coder/v2/provider"
)
type staticRender struct {
staticParams []previewtypes.Parameter
}
func (r *loader) staticRender(ctx context.Context, db database.Store) (*staticRender, error) {
dbTemplateVersionParameters, err := db.GetTemplateVersionParameters(ctx, r.templateVersionID)
if err != nil {
return nil, xerrors.Errorf("template version parameters: %w", err)
}
params := db2sdk.List(dbTemplateVersionParameters, TemplateVersionParameter)
for i, param := range params {
// Update the diagnostics to validate the 'default' value.
// We do not have a user supplied value yet, so we use the default.
params[i].Diagnostics = append(params[i].Diagnostics, previewtypes.Diagnostics(param.Valid(param.Value))...)
}
return &staticRender{
staticParams: params,
}, nil
}
func (r *staticRender) Render(_ context.Context, _ uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) {
params := r.staticParams
for i := range params {
param := &params[i]
paramValue, ok := values[param.Name]
if ok {
param.Value = previewtypes.StringLiteral(paramValue)
} else {
param.Value = param.DefaultValue
}
param.Diagnostics = previewtypes.Diagnostics(param.Valid(param.Value))
}
return &preview.Output{
Parameters: params,
}, hcl.Diagnostics{
{
// Only a warning because the form does still work.
Severity: hcl.DiagWarning,
Summary: "This template version is missing required metadata to support dynamic parameters.",
Detail: "To restore full functionality, please re-import the terraform as a new template version.",
},
}
}
func (*staticRender) Close() {}
func TemplateVersionParameter(it database.TemplateVersionParameter) previewtypes.Parameter {
param := previewtypes.Parameter{
ParameterData: previewtypes.ParameterData{
Name: it.Name,
DisplayName: it.DisplayName,
Description: it.Description,
Type: previewtypes.ParameterType(it.Type),
FormType: provider.ParameterFormType(it.FormType),
Styling: previewtypes.ParameterStyling{},
Mutable: it.Mutable,
DefaultValue: previewtypes.StringLiteral(it.DefaultValue),
Icon: it.Icon,
Options: make([]*previewtypes.ParameterOption, 0),
Validations: make([]*previewtypes.ParameterValidation, 0),
Required: it.Required,
Order: int64(it.DisplayOrder),
Ephemeral: it.Ephemeral,
Source: nil,
},
// Always use the default, since we used to assume the empty string
Value: previewtypes.StringLiteral(it.DefaultValue),
Diagnostics: make(previewtypes.Diagnostics, 0),
}
if it.ValidationError != "" || it.ValidationRegex != "" || it.ValidationMonotonic != "" {
var reg *string
if it.ValidationRegex != "" {
reg = ptr.Ref(it.ValidationRegex)
}
var vMin *int64
if it.ValidationMin.Valid {
vMin = ptr.Ref(int64(it.ValidationMin.Int32))
}
var vMax *int64
if it.ValidationMax.Valid {
vMax = ptr.Ref(int64(it.ValidationMax.Int32))
}
var monotonic *string
if it.ValidationMonotonic != "" {
monotonic = ptr.Ref(it.ValidationMonotonic)
}
param.Validations = append(param.Validations, &previewtypes.ParameterValidation{
Error: it.ValidationError,
Regex: reg,
Min: vMin,
Max: vMax,
Monotonic: monotonic,
})
}
var protoOptions []*sdkproto.RichParameterOption
err := json.Unmarshal(it.Options, &protoOptions)
if err != nil {
param.Diagnostics = append(param.Diagnostics, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Failed to parse json parameter options",
Detail: err.Error(),
})
}
for _, opt := range protoOptions {
param.Options = append(param.Options, &previewtypes.ParameterOption{
Name: opt.Name,
Description: opt.Description,
Value: previewtypes.StringLiteral(opt.Value),
Icon: opt.Icon,
})
}
// Take the form type from the ValidateFormType function. This is a bit
// unfortunate we have to do this, but it will return the default form_type
// for a given set of conditions.
_, param.FormType, _ = provider.ValidateFormType(provider.OptionType(param.Type), len(param.Options), param.FormType)
return param
}