diff --git a/internal/testprovider/schema_default_info.go b/internal/testprovider/schema_default_info.go new file mode 100644 index 000000000..2405301ac --- /dev/null +++ b/internal/testprovider/schema_default_info.go @@ -0,0 +1,66 @@ +// Copyright 2016-2023, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testprovider + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// Subset of pulumi-random provider. +func ProviderDefaultInfo() *schema.Provider { + resourceRuleset := func() *schema.Resource { + return &schema.Resource{ + Description: "Deploy a ruleset", + Schema: resourceDefaultInfoSchema(), + } + } + + return &schema.Provider{ + Schema: map[string]*schema.Schema{}, + ResourcesMap: map[string]*schema.Resource{ + "default_ruleset": resourceRuleset(), + }, + } +} + +func resourceDefaultInfoSchema() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the ruleset.", + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: "Brief summary of the ruleset and its intended use.", + }, + "rules": { + Type: schema.TypeList, + Optional: true, + Description: "List of rules to apply to the ruleset.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Unique rule identifier.", + }, + }, + }, + }, + } +} diff --git a/pkg/tfbridge/info.go b/pkg/tfbridge/info.go index d178e7ae0..427b15437 100644 --- a/pkg/tfbridge/info.go +++ b/pkg/tfbridge/info.go @@ -515,6 +515,8 @@ type DefaultInfo struct { ComputeDefault func(ctx context.Context, opts ComputeDefaultOptions) (interface{}, error) // Value injects a raw literal value as the default. + // Note that only simple types such as string, int and boolean are currently supported here. + // Structs, slices and maps are not yet supported. Value interface{} // EnvVars to use for defaults. If none of these variables have values at runtime, the value of `Value` (if any) // will be used as the default. diff --git a/pkg/tfgen/generate_schema.go b/pkg/tfgen/generate_schema.go index 65d70340c..558dedf97 100644 --- a/pkg/tfgen/generate_schema.go +++ b/pkg/tfgen/generate_schema.go @@ -22,6 +22,7 @@ import ( "bytes" "encoding/json" "fmt" + "reflect" "sort" "strings" @@ -553,6 +554,48 @@ func (g *schemaGenerator) genProperty(prop *variable) pschema.PropertySpec { if i, ok := defaultValue.(int); ok { defaultValue = float64(i) } + rt := reflect.TypeOf(defaultValue) + if rt != nil { + switch kind := rt.Kind(); kind { + case + reflect.Bool, + reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64, + reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Float32, + reflect.Float64, + reflect.String: + // These are fine. + case + reflect.Uintptr, + reflect.Complex64, + reflect.Complex128, + reflect.Array, + reflect.Chan, + reflect.Func, + reflect.Interface, + reflect.Map, + reflect.Pointer, + reflect.Slice, + reflect.Struct, + reflect.UnsafePointer: + fallthrough + default: + contract.Failf( + "Property %v has a DefaultInfo Value %v of kind %v which is not currently supported.", + prop.name, + prop.info.Default.Value, + kind.String(), + ) + } + } if len(defaults.EnvVars) != 0 { defaultInfo = &pschema.DefaultSpec{ diff --git a/pkg/tfgen/generate_schema_test.go b/pkg/tfgen/generate_schema_test.go index e4f8028a1..cd701b38e 100644 --- a/pkg/tfgen/generate_schema_test.go +++ b/pkg/tfgen/generate_schema_test.go @@ -368,3 +368,24 @@ func TestPropagateLanguageOptions(t *testing.T) { assert.Equal(t, "gradle", actual["buildFiles"]) }) } + +func TestDefaultInfoFails(t *testing.T) { + provider := testprovider.ProviderDefaultInfo() + meta, err := metadata.New(nil) + require.NoError(t, err) + provider.MetadataInfo = &tfbridge.MetadataInfo{ + Path: "non-nil", + Data: meta, + } + require.NoError(t, err) + defer func() { + r := recover() + assert.Contains( + t, + r, + "Property id has a DefaultInfo Value [default_id] of kind slice which is not currently supported.", + ) + }() + // Should panic + _, _ = GenerateSchema(provider, diag.DefaultSink(io.Discard, io.Discard, diag.FormatOptions{Color: colors.Never})) +} diff --git a/pkg/tfgen/internal/testprovider/defaultinfo.go b/pkg/tfgen/internal/testprovider/defaultinfo.go new file mode 100644 index 000000000..86c90aeae --- /dev/null +++ b/pkg/tfgen/internal/testprovider/defaultinfo.go @@ -0,0 +1,76 @@ +// Copyright 2016-2022, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testprovider + +import ( + "unicode" + + "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge" + shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2" + "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" + + testproviderdata "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testprovider" +) + +func ProviderDefaultInfo() tfbridge.ProviderInfo { + + member := func(mod string, mem string) tokens.ModuleMember { + return tokens.ModuleMember("cloudflare" + ":" + mod + ":" + mem) + } + + typ := func(mod string, typ string) tokens.Type { + return tokens.Type(member(mod, typ)) + } + + resource := func(mod string, res string) tokens.Type { + fn := string(unicode.ToLower(rune(res[0]))) + res[1:] + return typ(mod+"/"+fn, res) + } + + return tfbridge.ProviderInfo{ + P: shimv2.NewProvider(testproviderdata.ProviderDefaultInfo()), + Name: "default-info", + Description: "", + Keywords: []string{"pulumi", "random"}, + License: "Apache-2.0", + Homepage: "https://pulumi.io", + Repository: "", + Config: map[string]*tfbridge.SchemaInfo{ + "project": { + Default: &tfbridge.DefaultInfo{ + Value: []string{"default_project"}, + }, + }, + }, + Resources: map[string]*tfbridge.ResourceInfo{ + "default_ruleset": { + Tok: resource("index", "Ruleset"), + Fields: map[string]*tfbridge.SchemaInfo{ + "rules": { + Elem: &tfbridge.SchemaInfo{ + Fields: map[string]*tfbridge.SchemaInfo{ + "id": { + Default: &tfbridge.DefaultInfo{ + Value: []string{"default_id"}, + }, + }, + }, + }, + }, + }, + }, + }, + } +}